Notes on splitn -- TRANSP sub-system for namelist -- uses generated namelist descriptor data but does not use TRCOM directly. dmc 14 Dec 2003 (about 1 year after original code was written) dmc 14 Aug 2005 "steering" modification -- see section titled "steering test", below. dmc 24 Jun 2006 "namelist merge" operations -- see section titled "namelist section merges" below. jec 22 Aug 2007 splitn_io_list writeup added ---------------------------------------------- ---------------------------------------------- vision for xtranspin: call splitn_read(filename,ios) ... to read the TRANSP namelist database and load the splitn buffers. The main buffer is loaded from the specified file; default values from the defaults buffer are used for namelist variables and array elements whose values are not explicitly set by the file. a python-generated call sequence can load both the default values (splitn_getd.f90 calls) and the actual values (splitn_get.f90 calls or splitn_getf calls) from splitn into the xtranspin space [user & xtranspin do their thing] when xtranspin wants to write an edited namelist file: a python-generated call sequence can load from the xtranspin space into the splitn "write buffer" (splitn_putw calls). Then: call splitn_wtrans transfers data from the write buffer to the main buffer, while concurrently performing automatic edits on the namelist file text as stored in memory... these are "minimal edits" with comments and position of variables preserved "as much as possible" the same as was given in the original input file, and then call splitn_write(filename,ios) to send the edited text to a disk file. .... if now the python sequence of splitn_get.f90 calls were executed, it could "reload" the xtranspin space ... but, this should result in no change, if all is working as it should be. This might be a good test for the system. dmc 24 Dec 2003 -- the splitn calls have been alpha-tested and are ready to be deployed in xtranspin ... though some further careful testing would be advisable ... ---------------------------------------------- ---------------------------------------------- Steering test -- there is interest in being able to "steer" TRANSP runs, i.e. restart interrupted runs with changes to input data. Rules have been established in terms of what is and what is not allowed to change from the initial run to the restarted run. The splitn routine "splitn_diff" can be used to compare two namelists to see if their differences are compatible with the steering rules. (In general, the steering rules allow TRDAT-mediated input data to change: measured data, neutral beam injection powers and voltages, RF antenna powers, pellet and sawteeth event times, time of end of run, times for future requested interruptions to the run. Items other than these-- generally control options, and data read directly from the namelist into TRANSP without going through the TRDAT output file-- are not allowed to change on restart). The following code sequence can be used to test for steering compatibility of a restart namelist: call splitn_read(,ios) call splitn_read(,ios) lun_tty = 6 call splitn_diff(lun_tty,idiff,ierr) When the 2nd namelist is read, the 1st namelist's values are saved into a "differencing" buffer. The splitn_diff subroutine takes 3 arguments; the first is input, a Fortran LUN for messages (0 to suppress messages; 6 for stdout). The 2nd and 3rd arguments are output. The output argument "idiff" returns the number of legal, valid steering changes detected. The output argument "ierr" returns the number of invalid or unsupported changes (for each of which a warning message will also have been written). If splitn_diff is called but no previous namelist has been read, ierr=-1 is returned, meaning that no steering comparison is possible. ---------------------------------------------- ---------------------------------------------- Namelist section merges -- dmc Jun 2006. A routine has been added to splitn to enable a namelist fragment to be merged into a namelist. This can be done after reading a namelist in the normal way. This does: (a) optionally, save a backup copy of the namelist to file. (b) read the new namelist fragment with full parsing and error checking. (c) append fragment to end of original namelist (d) remove lines from original namelist that define variables defined in the fragment, or comments that share a tag with the fragment. The merged namelist is written to a file and then read back in, so that the namelist in splitn memory (text and variable values) is the new, merged namelist. ---------------- **note** when using this from xtranspin -- this should look to xtranspin like a write/read operation. Presumably "splitn_wtrans" has to be called prior to the write; the xtranspin internal copies of the namelist values will have to also be updated with the appropriate calls... ---------------- To use this new splitn feature, call the following new subroutine: subroutine splitn_merge_write(merge_input_filename, & backup_filename,output_filename, tagname, ios) ! save backup of current namelist, if backup_filename.ne.' ' ! merge namelist text with text from a namelist section ! (in file merge_input_filename) ! write merged list to output_filename ! read merged file back in if no error so far. ! tag merged lines with "!$". ! tags should be 1 word & short, such as "beam_info". use splitn_module implicit NONE character*(*), intent(in) :: merge_input_filename character*(*), intent(in) :: backup_filename character*(*), intent(in) :: output_filename character*(*), intent(in) :: tagname integer, intent(out) :: ios ! status code on exit, 0=normal ---------------------------------------------- ---------------------------------------------- splitn_test.for test program no modules or COMMON linkage: splitn_test.o, splitn.a, portlib.a read namelist: call splitn_read(zfile1,ios) lookup & print out some values (call splitn_iget, etc...) make modifications ... write out copies of modified namelist. splitn_wtrans test (with "random" namelist changes) is now included. write namelist: call splitn_write(zfile2,ios) ---------------------------------------------- splitn.for integer function splitn use splitn_module iret = splitn(...) (input arguments: file path & runid info -- see cmts) read specified namelist file, write TR.ZDA file containing namelists in fortran readable form. Calls to: splitn_read splitn_f77 This is what TRANSP/TRDAT/PRETR call. ---------------------------------------------- splitn_read.f90 subroutine splitn_read(filename,ios) use splitn_module read namelist by calling read_nl (contained routine in module) ---------------------------------------------- splitn_write.f90 subroutine splitn_write(filename,ios) use splitn_module write namelist by calling write_nl (contained routine in module) ++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++ splitn_module.f90 the f90 module for the splitn subroutine library the module is private to the splitn.a subroutine library data elements: nlines, textnl, ordl, lenl, ... TR.DAT file text namfld(1:2,ordl(j)) -- name field, j'th line start:end valfld(1:2,ordl(j)) -- value field, j'th line start:end cmtfld(ordl(j)) -- start of comment, j'th line length of line = abs(lenl(j)); sign(lenl(j)) indicates EFIT imbedded, or other "special" namelist data. namelist database: nlfile -- filename have_database -- .FALSE. until database has been read. cur_naml -- current namelist indicator output (fortran readable) namelists: max_namls, nnamls; Character*8 all_namls(max_namls) maxrank = 4 = max dimensionality of arrays var datatype: name: variable name type: R/I/L/D or C*n C*nn C*nnn naml: output (f77) namelist to which it belongs chsize: size n of C*n strings rank: dimensionality of arrays (0,1,2,3, up to maxrank) dims(2:maxrank) -- each dimension lower:upper limit C*20 short_dflt -- default value string (if short) long_dflt_addr -- default value string (if long) addr -- pointer to data (as per type) nlinadr -- ptr to iline array which specifies the TR.DAT file lines defining variable nvars -- no. of vars -- varlist(1:nvars) (type var) -- variables integer var_order(1:nvars) -- alphabetic order buffers for value fields -- all dimensioned the same logbuf(1:nlog) defaults: logbuf_d write buffer: logbuf_w intbuf(1:nint) defaults: intbuf_d write buffer: intbuf_w rbuf(1:nreal) defaults: rbuf_d write buffer: rbuf_w dbuf(1:nr8) defaults: dbuf_d write buffer: dbuf_w c*128 chbuf(1:nchv) defaults: chbuf_d write buffer: chbuf_w the dimensions are added up from the namelist database $CONFIGDIR/nxlist.summary dimensioning is set by reading the namelist spec (pass #1) and then values filled in by reading it again (pass #2). ilines(...),ivrange(...) location of value specifications for variables, in original TR.DAT file. One for each array element in the namelist object. 0 value means element is defaulted (not specified in the user TR.DAT file). krepeat(...),irrange(...) location of corresponding repeat count parsing info: lists of doubly assigned values & floats with missing decimal pts. contained routines: init_nl -- init arrays for readin of namelist read_nl -- read namelist parse_line -- parse one line write_nl -- write namelist add_nl_line -- add line to module TR.DAT file image read_db -- read namelist spec database igsize -- compute size of array object insert_var -- add var to list, tracking alphabetic order iorder -- alphabetic order set_zdflt -- get default value string rset_dflt -- set R default values dset_dflt -- set R*8 default values iset_dflt -- set I default values lset_dflt -- set L default values chset_dflt -- set CH default values icomma_get -- find comma in default string read1_db -- read 1 line from database & parse addlist -- add to list of known output namelists ++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++ ---------------------------------------------- splitn_f77.f90 subroutine splitn_f77(zfile,ios) use splitn_module write TR.ZDA file for readin by standard TRANSP namelist readers (TRCOM COMMON; trngen.for) uses module i/o lun (default value: 82). loop over f77 namelists; write each one loop over all namelist names -- insert into current namelist write values as char strings as found in original file write array elements' value assignments one element at a time ---------------------------------------------- "mid level routines" splitn_chkdp.f90 use splitn_module check that all floating point values have decimal points; insert if necessary called from splitn_module contained routine "parse_line". calls: splitn_nxgrp, splitn_addwarn splitn_lhs.for use splitn_module decode LHS of "name = value" line in namelist file In the LHS, find what variable is being assigned, and if an array element which one. Perform bounds checks on array subscripts; make sure no. of subscripts matches rank of the array (error messages on unit 6). called from contained routine "parse_line" in splitn_module.f90. calls out to: idcod_splitn splitn_rhs0.for use splitn_module check RHS of scalar value assignment; fetch values called from splitn_module, contained routine parse_line calls out to: splitn_nxgrp, splitn_*dcod, splitn_addwarn splitn_rhs.for use splitn_module check RHS of value assignment: array or set of array elements; fetch values. called from splitn_module, contained routine parse_line calls out to: splitn_nxgrp, splitn_*dcod, splitn_addwarn ---------------------------------------------- "low level routines" idcod_splitn.for integer function idcod_splitn(zint,ierr) no modules or COMMON translate passed string into integer, if possible used by splitn_lhs splitn_addwarn.f90 no modules or COMMON add a name to a short list of names, maintaining alphabetic order. this is a list of names about which a warning is to be printed later. used by splitn_chkdup, splitn_rhs, splitn_rhs0 splitn_lunset.f90 subroutine splitn_lunset(ilun) use splitn_module subroutine splitn_lunget(ilun) use splitn_module set/get LUN for splitn file operations not currently used by TRANSP default LUN value is used: 82 splitn_dcod.f90 decode string; put n copies into output buffer; error msgs -> unit 6 string is passed as word with no leading/trailing blanks. splitn_idcod,splitn_rdcod,splitn_ddcod,splitn_ldcod,splitn_cdcod no modules or COMMON used by splitn_rhs & splitn_rhs0 splitn_get.f90 use splitn_module get values of namelist objects; names & values as stored in the module. error msgs -> unit 6, if passed name, type and size of object are not consistent with what was read from the namelist database. splitn_iget,splitn_rget,splitn_dget,splitn_lget,splitn_cget The values returned are the default values (for elements not set by the namelist file) or actual values from the namelist file. used by splitn_test splitn_getf.f90 use splitn_module get values of namelist objects; names & values as stored in the module. error msgs -> unit 6, if passed name, type and size of object are not consistent with what was read from the namelist database. splitn_igetf,splitn_rgetf,splitn_dgetf,splitn_lgetf,splitn_cgetf **only** values explicitly set in the namelist file are set; other element values are returned unmodified. used by splitn_test splitn_getd.f90 use splitn_module get *default* values of namelist objects; names & values as stored in the module. error msgs -> unit 6, if passed name, type and size of object are not consistent with what was read from the namelist database. splitn_iget,splitn_rget,splitn_dget,splitn_lget,splitn_cget splitn_io_list( ixspl, cspl, istat ) jec 22Aug2007 returns in cspl, an array of strings containing Ufile definitions - cTri//cPre//cExt . ixspl should be zero before first call. If number of files exceeds dimension of cspl, istat = 1 and a subsequent call, with ixspl unchanged, will return the next set of values. cspl may have dimesion 1 to step through the Ufiles one at a time. When all cards have been returned - ixspl = -1 cspl(1:4) = ' ' for undefined entries ( beyond last file ) istat = 0 Note that 4 characters are allocated to the trigraph field. The 4th character is blank, unless the card contains an array element, in which case this character is the array subscript, leading to 'trigraphs' SIM1, SIM2 etc. See splitn_test for example of use splitn_putw.f90 use splitn_module write namelist objects (as modified) into the write buffer. use "call splitn_wtrans" to transfer data from write buffer to main buffer with concurrent automatic editing of main buffer namelist file text. splitn_nxgrp.for subroutine splitn_nxgrp(...) no module or COMMON get next group of values on RHS of "name=value" expression; deal with repeat counts nn* as well as nulls ",," to leave an element unaffected in an array namelist value specification. called by: splitn_chkdp, splitn_rhs0, splitn_rhs splitn_printwarn.f90 subroutine splitn_printwarn no module or COMMON print warning message (unit 6) along with list of affected names. called from inside contained routines of the splitn_module. -------------------------------------------- -------------------------------------------- the following update the main buffer **and the file text** as will be written by subsequent splitn_write call. If the write buffer has been updated, then the single call call splitn_wtrans will transfer the write buffer contents to the main buffer, with concurrent update of file text (i.e. automatic editing). splitn_put --> splitn_iput_sc,splitn_lput_sc,splitn_dput_sc,splitn_chput_sc ... update scalar variables of various types splitn_puta --> splitn_iput_ar,splitn_lput_ar,splitn_dput_ar,splitn_chput_ar ... update sections of array variables (single update value, consecutive elements changed). ========================================================================= ========================================================================= Additional observation about splitn: -- it is not "MDSplus aware". To operate on a TRANSP namelist stored in an MDSplus tree, the calling code must extract that namelist to a file first, and pass splitn_read the name of the extracted temporary file.