MDSplus / mdsplus

The MDSplus data management system
https://mdsplus.org/
Other
71 stars 43 forks source link

tdi function pointer to subtree/node breaks across pulses #1785

Closed VadimNV closed 5 years ago

VadimNV commented 5 years ago

Dear MDSplus developers team,

There is a bug in the way TDI functions caches/stores their "pointers" to the nodes and/or subtrees. It seems that the issue is due to a given node changing its NID_NUMBER between some pulse number ($SHOT) After looking into this for a while, here is the information that can be useful. If there is a TDI command that can read node data by the NID_NUMBER rathar than by the node name/path - please share, this would be very useful. Thanks in advance!

1) simple test tdi function "simple_test.fun": PUBLIC SIMPLE_TEST(IN _name, IN _IOtype) { WRITE(,data(raw_mag.acq2106_034:_DT)); WRITE(,getnci("raw_mag.acq2106_034","NID_NUMBER"));

WRITE(,data(pss.PF_CONFIG)); WRITE(,getnci("pss","NID_NUMBER"));

RETURN("TESTING"); } 2) here "ST40" is a main tree, "raw_mag" and "PSS" are subtrees. In my tests ".acq2106_034:_DT" is a NUMERIC node storing a value of 1.0; "PF_CONFIG" is a NUMERIC node node storing 1.0 or $ROPRAND depending on $SHOT. There is also a tree called "ECE" with a HELP node storing a string "This tree stores data from the Electron Cyclotron Emission"

3) Hypothesis: when you connect to MDSplus server for the first time, a TDI function caches (stores) the subtree and/or node id numbers ( getnci("nodeName","NID_NUMBER") ). When, within the same session/connection, one opens a tree where the node of interest has a distinct NID_NUMBER between different $SHOT numbers, the TDI function tries to read from the wrong place. Sometimes, by chance, it returns the data from a different node, other times it returns / bad / if no node exists under the cached NID_NUMBER.

4) from command line, start TDI and run tests $tdic TDI> treeopen('st40',6066) TDI> simple_test("I_TF_PSU","ain") 1.00000E0 50331649 $ROPRAND # CORRECT OUTPUT 234881024 # SAME NID_NUMBER - OK "TESTING" TDI> treeopen('st40',6067) 265388067 TDI> simple_test("I_TF_PSU","ain") 1.00000E0 50331649 $ROPRAND # CORRECT OUTPUT 234881024 # SAME NID_NUMBER - OK "TESTING" TDI> treeopen('st40',6068) 265388067 TDI> simple_test("I_TF_PSU","ain") 1.00000E0 50331649 This tree stores data from the Electron Cyclotron Emission # WRONG TREE/NODE DATA 251658240 # NEW NID_NUMBER ! ! ! "TESTING" TDI> WRITE(,data(pss.PF_CONFIG)); $ROPRAND # BUT THIS WORKS, SINCE TDI FUNCTION CACHE ISN'T USED (???) TDI> WRITE(,data(ECE.HELP)); This tree stores data from the Electron Cyclotron Emission TDI> WRITE(*,getnci("ECE.HELP","NID_NUMBER")); 234881025 TDI> exit $ tdic TDI>TDI> treeopen('st40',6068) 265388067 TDI> simple_test("I_TF_PSU","ain") 1.00000E0 50331649 $ROPRAND #WORKS IF TDI FUNCTION "CACHE" is reloaded ??? 251658240 "TESTING"

VadimNV commented 5 years ago

Hi again,

I may add that this might be related to ISSUES #1518 and #1519, posted by Otto Asunta. The "simple_test.FUN" function above, is a stripped down version of the "find_analogue_signal.fun", where the issue was traced to the inability to read data from a node, across some special $SHOT numbers.

Regards, Vadim

VadimNV commented 5 years ago

One last thing,

I printed the NID_NUMBER for the less informative PSS tree rather than PSS.PF_CONFIG that I am trying to read from in my TDI function.

Here's the relevant info, confirming my hypothesis TDI> treeopen('st40',6068) TDI> WRITE(,getnci("PSS.PF_CONFIG","NID_NUMBER")); 251658241 TDI> WRITE(,getnci("ECE.HELP","NID_NUMBER")); 234881025 TDI> treeopen('st40',6066) 265388067 TDI> WRITE(*,getnci("PSS.PF_CONFIG","NID_NUMBER")); 234881025

VadimNV commented 5 years ago

Hi again,

OK I have come across a way to circumvent the bug I think... Inside the TDI function:

/ this works / if_error(_nid = getnci("pss.ai:list", "NID_NUMBER"), _nid=-2);
if_error(_l1= data(getnci(_nid, "record")),_l1=[]);

/ this throws error across some $SHOT numbers / if_error(_l1= data(pss.ai:list),_l1=[]);

VadimNV commented 5 years ago

instead of pss.ai:list, can add any PSS node

tfredian commented 5 years ago

When TDI functions are first referenced they are compiled using the tree context at the time they were first referenced. If a node is referenced directly by a TDI expression the node is located and converted to a NID during compilation. Unfortunately, I was unable to find the solution for this in the online MDSplus documentation so apparently the work around has only been passed around by word of mouth it seems.

When referencing nodes in a TDI expression you should always use the build_path() function with a string argument containing the node path. This defers the lookup of the node until the time when the expression is evaluated instead of when it is compiled. The node will be located based on the tree context and current default node of the session at the time of evaluation so it is often advised that the full path string for the node be used instead of a relative node references. Note that if the string contains a leading backslash you need to use two backslashes (i.e. build_path("\mytree::top.foo:bar").

I will add the "Documentation needed" tag to this issue.

zack-vii commented 5 years ago

or we could consider somehow prevent treepaths to be evaluated if inside of a tdi function.

the omit arg of data may be of use.

tfredian commented 5 years ago

We do replace nids with paths with build_path() references when expressions written to trees reference nodes from other trees. We could possibly have compile generate build_path() calls instead of nids when processing a tdi fun compilation but I'm not sure how complicated that might be. As I said, this has been a known behavior that users have worked around for decades by simply using build_path() calls in tdi fun definitions. It was just never properly documented on the www.mdsplus.org web site. The use of node references in tdi funs is not a common practice in general. I'm not sure what you mean by "the omit arg of data may be of use".

zack-vii commented 5 years ago

fixed by #1789