PageRenderTime 51ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 1ms

/src/variable.cpp

http://github.com/browndeer/lammps-ocl
C++ | 3292 lines | 2461 code | 468 blank | 363 comment | 1971 complexity | 69e4d1cb2dc7d06c3b0b8785f6eb5c5a MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /* ----------------------------------------------------------------------
  2. LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
  3. http://lammps.sandia.gov, Sandia National Laboratories
  4. Steve Plimpton, sjplimp@sandia.gov
  5. Copyright (2003) Sandia Corporation. Under the terms of Contract
  6. DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
  7. certain rights in this software. This software is distributed under
  8. the GNU General Public License.
  9. See the README file in the top-level LAMMPS directory.
  10. ------------------------------------------------------------------------- */
  11. #include "math.h"
  12. #include "stdlib.h"
  13. #include "string.h"
  14. #include "ctype.h"
  15. #include "unistd.h"
  16. #include "variable.h"
  17. #include "universe.h"
  18. #include "atom.h"
  19. #include "update.h"
  20. #include "group.h"
  21. #include "domain.h"
  22. #include "region.h"
  23. #include "modify.h"
  24. #include "compute.h"
  25. #include "fix.h"
  26. #include "output.h"
  27. #include "thermo.h"
  28. #include "random_mars.h"
  29. #include "memory.h"
  30. #include "error.h"
  31. using namespace LAMMPS_NS;
  32. #define VARDELTA 4
  33. #define MAXLEVEL 4
  34. #define MIN(A,B) ((A) < (B)) ? (A) : (B)
  35. #define MAX(A,B) ((A) > (B)) ? (A) : (B)
  36. #define MYROUND(a) (( a-floor(a) ) >= .5) ? ceil(a) : floor(a)
  37. enum{INDEX,LOOP,WORLD,UNIVERSE,ULOOP,STRING,EQUAL,ATOM};
  38. enum{ARG,OP};
  39. // customize by adding a function
  40. enum{DONE,ADD,SUBTRACT,MULTIPLY,DIVIDE,CARAT,UNARY,
  41. NOT,EQ,NE,LT,LE,GT,GE,AND,OR,
  42. SQRT,EXP,LN,LOG,SIN,COS,TAN,ASIN,ACOS,ATAN,ATAN2,
  43. RANDOM,NORMAL,CEIL,FLOOR,ROUND,RAMP,STAGGER,LOGFREQ,
  44. VDISPLACE,SWIGGLE,CWIGGLE,GMASK,RMASK,GRMASK,
  45. VALUE,ATOMARRAY,TYPEARRAY,INTARRAY};
  46. // customize by adding a special function
  47. enum{SUM,XMIN,XMAX,AVE,TRAP};
  48. #define INVOKED_SCALAR 1
  49. #define INVOKED_VECTOR 2
  50. #define INVOKED_ARRAY 4
  51. #define INVOKED_PERATOM 8
  52. #define BIG 1.0e20
  53. /* ---------------------------------------------------------------------- */
  54. Variable::Variable(LAMMPS *lmp) : Pointers(lmp)
  55. {
  56. MPI_Comm_rank(world,&me);
  57. nvar = maxvar = 0;
  58. names = NULL;
  59. style = NULL;
  60. num = NULL;
  61. which = NULL;
  62. pad = NULL;
  63. data = NULL;
  64. randomequal = NULL;
  65. randomatom = NULL;
  66. precedence[DONE] = 0;
  67. precedence[OR] = 1;
  68. precedence[AND] = 2;
  69. precedence[EQ] = precedence[NE] = 3;
  70. precedence[LT] = precedence[LE] = precedence[GT] = precedence[GE] = 4;
  71. precedence[ADD] = precedence[SUBTRACT] = 5;
  72. precedence[MULTIPLY] = precedence[DIVIDE] = 6;
  73. precedence[CARAT] = 7;
  74. precedence[UNARY] = precedence[NOT] = 8;
  75. PI = 4.0*atan(1.0);
  76. }
  77. /* ---------------------------------------------------------------------- */
  78. Variable::~Variable()
  79. {
  80. for (int i = 0; i < nvar; i++) {
  81. delete [] names[i];
  82. if (style[i] == LOOP || style[i] == ULOOP) delete [] data[i][0];
  83. else for (int j = 0; j < num[i]; j++) delete [] data[i][j];
  84. delete [] data[i];
  85. }
  86. memory->sfree(names);
  87. memory->destroy(style);
  88. memory->destroy(num);
  89. memory->destroy(which);
  90. memory->destroy(pad);
  91. memory->sfree(data);
  92. delete randomequal;
  93. delete randomatom;
  94. }
  95. /* ----------------------------------------------------------------------
  96. called by variable command in input script
  97. ------------------------------------------------------------------------- */
  98. void Variable::set(int narg, char **arg)
  99. {
  100. if (narg < 2) error->all("Illegal variable command");
  101. // DELETE
  102. // doesn't matter if variable no longer exists
  103. if (strcmp(arg[1],"delete") == 0) {
  104. if (narg != 2) error->all("Illegal variable command");
  105. if (find(arg[0]) >= 0) remove(find(arg[0]));
  106. return;
  107. // INDEX
  108. // num = listed args, which = 1st value, data = copied args
  109. } else if (strcmp(arg[1],"index") == 0) {
  110. if (narg < 3) error->all("Illegal variable command");
  111. if (find(arg[0]) >= 0) return;
  112. if (nvar == maxvar) extend();
  113. style[nvar] = INDEX;
  114. num[nvar] = narg - 2;
  115. which[nvar] = 0;
  116. pad[nvar] = 0;
  117. data[nvar] = new char*[num[nvar]];
  118. copy(num[nvar],&arg[2],data[nvar]);
  119. // LOOP
  120. // 1 arg + pad: num = N, which = 1st value, data = single string
  121. // 2 args + pad: num = N2, which = N1, data = single string
  122. } else if (strcmp(arg[1],"loop") == 0) {
  123. if (find(arg[0]) >= 0) return;
  124. if (nvar == maxvar) extend();
  125. style[nvar] = LOOP;
  126. int nfirst,nlast;
  127. if (narg == 3 || (narg == 4 && strcmp(arg[3],"pad") == 0)) {
  128. nfirst = 1;
  129. nlast = atoi(arg[2]);
  130. if (nlast <= 0) error->all("Illegal variable command");
  131. if (narg == 4 && strcmp(arg[3],"pad") == 0) {
  132. char digits[12];
  133. sprintf(digits,"%d",nlast);
  134. pad[nvar] = strlen(digits);
  135. } else pad[nvar] = 0;
  136. } else if (narg == 4 || (narg == 5 && strcmp(arg[4],"pad") == 0)) {
  137. nfirst = atoi(arg[2]);
  138. nlast = atoi(arg[3]);
  139. if (nfirst > nlast || nlast <= 0) error->all("Illegal variable command");
  140. if (narg == 5 && strcmp(arg[4],"pad") == 0) {
  141. char digits[12];
  142. sprintf(digits,"%d",nlast);
  143. pad[nvar] = strlen(digits);
  144. } else pad[nvar] = 0;
  145. } else error->all("Illegal variable command");
  146. num[nvar] = nlast;
  147. which[nvar] = nfirst-1;
  148. data[nvar] = new char*[1];
  149. data[nvar][0] = NULL;
  150. // WORLD
  151. // num = listed args, which = partition this proc is in, data = copied args
  152. // error check that num = # of worlds in universe
  153. } else if (strcmp(arg[1],"world") == 0) {
  154. if (narg < 3) error->all("Illegal variable command");
  155. if (find(arg[0]) >= 0) return;
  156. if (nvar == maxvar) extend();
  157. style[nvar] = WORLD;
  158. num[nvar] = narg - 2;
  159. if (num[nvar] != universe->nworlds)
  160. error->all("World variable count doesn't match # of partitions");
  161. which[nvar] = universe->iworld;
  162. pad[nvar] = 0;
  163. data[nvar] = new char*[num[nvar]];
  164. copy(num[nvar],&arg[2],data[nvar]);
  165. // UNIVERSE and ULOOP
  166. // for UNIVERSE: num = listed args, data = copied args
  167. // for ULOOP: num = N, data = single string
  168. // which = partition this proc is in
  169. // universe proc 0 creates lock file
  170. // error check that all other universe/uloop variables are same length
  171. } else if (strcmp(arg[1],"universe") == 0 || strcmp(arg[1],"uloop") == 0) {
  172. if (strcmp(arg[1],"universe") == 0) {
  173. if (narg < 3) error->all("Illegal variable command");
  174. if (find(arg[0]) >= 0) return;
  175. if (nvar == maxvar) extend();
  176. style[nvar] = UNIVERSE;
  177. num[nvar] = narg - 2;
  178. data[nvar] = new char*[num[nvar]];
  179. copy(num[nvar],&arg[2],data[nvar]);
  180. } else if (strcmp(arg[1],"uloop") == 0) {
  181. if (narg < 3 || narg > 4 || (narg == 4 && strcmp(arg[3],"pad") != 0))
  182. error->all("Illegal variable command");
  183. if (find(arg[0]) >= 0) return;
  184. if (nvar == maxvar) extend();
  185. style[nvar] = ULOOP;
  186. num[nvar] = atoi(arg[2]);
  187. data[nvar] = new char*[1];
  188. data[nvar][0] = NULL;
  189. if (narg == 4) {
  190. char digits[12];
  191. sprintf(digits,"%d",num[nvar]);
  192. pad[nvar] = strlen(digits);
  193. } else pad[nvar] = 0;
  194. }
  195. if (num[nvar] < universe->nworlds)
  196. error->all("Universe/uloop variable count < # of partitions");
  197. which[nvar] = universe->iworld;
  198. if (universe->me == 0) {
  199. FILE *fp = fopen("tmp.lammps.variable","w");
  200. fprintf(fp,"%d\n",universe->nworlds);
  201. fclose(fp);
  202. }
  203. for (int jvar = 0; jvar < nvar; jvar++)
  204. if (num[jvar] && (style[jvar] == UNIVERSE || style[jvar] == ULOOP) &&
  205. num[nvar] != num[jvar])
  206. error->all("All universe/uloop variables must have same # of values");
  207. // STRING
  208. // remove pre-existing var if also style STRING (allows it to be reset)
  209. // num = 1, which = 1st value
  210. // data = 1 value, string to eval
  211. } else if (strcmp(arg[1],"string") == 0) {
  212. if (narg != 3) error->all("Illegal variable command");
  213. if (find(arg[0]) >= 0) {
  214. if (style[find(arg[0])] != STRING)
  215. error->all("Cannot redefine variable as a different style");
  216. remove(find(arg[0]));
  217. }
  218. if (nvar == maxvar) extend();
  219. style[nvar] = STRING;
  220. num[nvar] = 1;
  221. which[nvar] = 0;
  222. pad[nvar] = 0;
  223. data[nvar] = new char*[num[nvar]];
  224. copy(1,&arg[2],data[nvar]);
  225. // EQUAL
  226. // remove pre-existing var if also style EQUAL (allows it to be reset)
  227. // num = 2, which = 1st value
  228. // data = 2 values, 1st is string to eval, 2nd is filled on retrieval
  229. } else if (strcmp(arg[1],"equal") == 0) {
  230. if (narg != 3) error->all("Illegal variable command");
  231. if (find(arg[0]) >= 0) {
  232. if (style[find(arg[0])] != EQUAL)
  233. error->all("Cannot redefine variable as a different style");
  234. remove(find(arg[0]));
  235. }
  236. if (nvar == maxvar) extend();
  237. style[nvar] = EQUAL;
  238. num[nvar] = 2;
  239. which[nvar] = 0;
  240. pad[nvar] = 0;
  241. data[nvar] = new char*[num[nvar]];
  242. copy(1,&arg[2],data[nvar]);
  243. data[nvar][1] = NULL;
  244. // ATOM
  245. // remove pre-existing var if also style ATOM (allows it to be reset)
  246. // num = 1, which = 1st value
  247. // data = 1 value, string to eval
  248. } else if (strcmp(arg[1],"atom") == 0) {
  249. if (narg != 3) error->all("Illegal variable command");
  250. if (find(arg[0]) >= 0) {
  251. if (style[find(arg[0])] != ATOM)
  252. error->all("Cannot redefine variable as a different style");
  253. remove(find(arg[0]));
  254. }
  255. if (nvar == maxvar) extend();
  256. style[nvar] = ATOM;
  257. num[nvar] = 1;
  258. which[nvar] = 0;
  259. pad[nvar] = 0;
  260. data[nvar] = new char*[num[nvar]];
  261. copy(1,&arg[2],data[nvar]);
  262. } else error->all("Illegal variable command");
  263. // set name of variable
  264. // must come at end, since STRING/EQUAL/ATOM reset may have removed name
  265. // name must be all alphanumeric chars or underscores
  266. int n = strlen(arg[0]) + 1;
  267. names[nvar] = new char[n];
  268. strcpy(names[nvar],arg[0]);
  269. for (int i = 0; i < n-1; i++)
  270. if (!isalnum(names[nvar][i]) && names[nvar][i] != '_')
  271. error->all("Variable name must be alphanumeric or "
  272. "underscore characters");
  273. nvar++;
  274. }
  275. /* ----------------------------------------------------------------------
  276. INDEX variable created by command-line argument
  277. make it INDEX rather than STRING so cannot be re-defined in input script
  278. ------------------------------------------------------------------------- */
  279. void Variable::set(char *name, int narg, char **arg)
  280. {
  281. char **newarg = new char*[2+narg];
  282. newarg[0] = name;
  283. newarg[1] = (char *) "index";
  284. for (int i = 0; i < narg; i++) newarg[2+i] = arg[i];
  285. set(2+narg,newarg);
  286. delete [] newarg;
  287. }
  288. /* ----------------------------------------------------------------------
  289. increment variable(s)
  290. return 0 if OK if successfully incremented
  291. return 1 if any variable is exhausted, free the variable to allow re-use
  292. ------------------------------------------------------------------------- */
  293. int Variable::next(int narg, char **arg)
  294. {
  295. int ivar;
  296. if (narg == 0) error->all("Illegal next command");
  297. // check that variables exist and are all the same style
  298. // exception: UNIVERSE and ULOOP variables can be mixed in same next command
  299. for (int iarg = 0; iarg < narg; iarg++) {
  300. ivar = find(arg[iarg]);
  301. if (ivar == -1) error->all("Invalid variable in next command");
  302. if (style[ivar] == ULOOP && style[find(arg[0])] == UNIVERSE) continue;
  303. else if (style[ivar] == UNIVERSE && style[find(arg[0])] == ULOOP) continue;
  304. else if (style[ivar] != style[find(arg[0])])
  305. error->all("All variables in next command must be same style");
  306. }
  307. // invalid styles STRING or EQUAL or WORLD or ATOM
  308. int istyle = style[find(arg[0])];
  309. if (istyle == STRING || istyle == EQUAL || istyle == WORLD || istyle == ATOM)
  310. error->all("Invalid variable style with next command");
  311. // increment all variables in list
  312. // if any variable is exhausted, set flag = 1 and remove var to allow re-use
  313. int flag = 0;
  314. if (istyle == INDEX || istyle == LOOP) {
  315. for (int iarg = 0; iarg < narg; iarg++) {
  316. ivar = find(arg[iarg]);
  317. which[ivar]++;
  318. if (which[ivar] >= num[ivar]) {
  319. flag = 1;
  320. remove(ivar);
  321. }
  322. }
  323. } else if (istyle == UNIVERSE || istyle == ULOOP) {
  324. // wait until lock file can be created and owned by proc 0 of this world
  325. // read next available index and Bcast it within my world
  326. // set all variables in list to nextindex
  327. int nextindex;
  328. if (me == 0) {
  329. while (1) {
  330. if (!rename("tmp.lammps.variable","tmp.lammps.variable.lock")) break;
  331. usleep(100000);
  332. }
  333. FILE *fp = fopen("tmp.lammps.variable.lock","r");
  334. fscanf(fp,"%d",&nextindex);
  335. fclose(fp);
  336. fp = fopen("tmp.lammps.variable.lock","w");
  337. fprintf(fp,"%d\n",nextindex+1);
  338. fclose(fp);
  339. rename("tmp.lammps.variable.lock","tmp.lammps.variable");
  340. if (universe->uscreen)
  341. fprintf(universe->uscreen,
  342. "Increment via next: value %d on partition %d\n",
  343. nextindex+1,universe->iworld);
  344. if (universe->ulogfile)
  345. fprintf(universe->ulogfile,
  346. "Increment via next: value %d on partition %d\n",
  347. nextindex+1,universe->iworld);
  348. }
  349. MPI_Bcast(&nextindex,1,MPI_INT,0,world);
  350. for (int iarg = 0; iarg < narg; iarg++) {
  351. ivar = find(arg[iarg]);
  352. which[ivar] = nextindex;
  353. if (which[ivar] >= num[ivar]) {
  354. flag = 1;
  355. remove(ivar);
  356. }
  357. }
  358. }
  359. return flag;
  360. }
  361. /* ----------------------------------------------------------------------
  362. return ptr to the data text associated with a variable
  363. if INDEX or WORLD or UNIVERSE or STRING var, return ptr to stored string
  364. if LOOP or ULOOP var, write int to data[0] and return ptr to string
  365. if EQUAL var, evaluate variable and put result in str
  366. if ATOM var, return NULL
  367. return NULL if no variable or which is bad, caller must respond
  368. ------------------------------------------------------------------------- */
  369. char *Variable::retrieve(char *name)
  370. {
  371. int ivar = find(name);
  372. if (ivar == -1) return NULL;
  373. if (which[ivar] >= num[ivar]) return NULL;
  374. char *str;
  375. if (style[ivar] == INDEX || style[ivar] == WORLD ||
  376. style[ivar] == UNIVERSE || style[ivar] == STRING) {
  377. str = data[ivar][which[ivar]];
  378. } else if (style[ivar] == LOOP || style[ivar] == ULOOP) {
  379. char result[16];
  380. if (pad[ivar] == 0) sprintf(result,"%d",which[ivar]+1);
  381. else {
  382. char padstr[16];
  383. sprintf(padstr,"%%0%dd",pad[ivar]);
  384. sprintf(result,padstr,which[ivar]+1);
  385. }
  386. int n = strlen(result) + 1;
  387. delete [] data[ivar][0];
  388. data[ivar][0] = new char[n];
  389. strcpy(data[ivar][0],result);
  390. str = data[ivar][0];
  391. } else if (style[ivar] == EQUAL) {
  392. char result[32];
  393. double answer = evaluate(data[ivar][0],NULL);
  394. sprintf(result,"%.10g",answer);
  395. int n = strlen(result) + 1;
  396. if (data[ivar][1]) delete [] data[ivar][1];
  397. data[ivar][1] = new char[n];
  398. strcpy(data[ivar][1],result);
  399. str = data[ivar][1];
  400. } else if (style[ivar] == ATOM) return NULL;
  401. return str;
  402. }
  403. /* ----------------------------------------------------------------------
  404. return result of equal-style variable evaluation
  405. ------------------------------------------------------------------------- */
  406. double Variable::compute_equal(int ivar)
  407. {
  408. return evaluate(data[ivar][0],NULL);
  409. }
  410. /* ----------------------------------------------------------------------
  411. compute result of atom-style variable evaluation
  412. only computed for atoms in igroup, else result is 0.0
  413. answers are placed every stride locations into result
  414. if sumflag, add variable values to existing result
  415. ------------------------------------------------------------------------- */
  416. void Variable::compute_atom(int ivar, int igroup,
  417. double *result, int stride, int sumflag)
  418. {
  419. Tree *tree;
  420. double tmp = evaluate(data[ivar][0],&tree);
  421. tmp = collapse_tree(tree);
  422. int groupbit = group->bitmask[igroup];
  423. int *mask = atom->mask;
  424. int nlocal = atom->nlocal;
  425. if (sumflag == 0) {
  426. int m = 0;
  427. for (int i = 0; i < nlocal; i++) {
  428. if (mask[i] && groupbit) result[m] = eval_tree(tree,i);
  429. else result[m] = 0.0;
  430. m += stride;
  431. }
  432. } else {
  433. int m = 0;
  434. for (int i = 0; i < nlocal; i++) {
  435. if (mask[i] && groupbit) result[m] += eval_tree(tree,i);
  436. m += stride;
  437. }
  438. }
  439. free_tree(tree);
  440. }
  441. /* ----------------------------------------------------------------------
  442. search for name in list of variables names
  443. return index or -1 if not found
  444. ------------------------------------------------------------------------- */
  445. int Variable::find(char *name)
  446. {
  447. for (int i = 0; i < nvar; i++)
  448. if (strcmp(name,names[i]) == 0) return i;
  449. return -1;
  450. }
  451. /* ----------------------------------------------------------------------
  452. return 1 if variable is EQUAL style, 0 if not
  453. ------------------------------------------------------------------------- */
  454. int Variable::equalstyle(int ivar)
  455. {
  456. if (style[ivar] == EQUAL) return 1;
  457. return 0;
  458. }
  459. /* ----------------------------------------------------------------------
  460. return 1 if variable is ATOM style, 0 if not
  461. ------------------------------------------------------------------------- */
  462. int Variable::atomstyle(int ivar)
  463. {
  464. if (style[ivar] == ATOM) return 1;
  465. return 0;
  466. }
  467. /* ----------------------------------------------------------------------
  468. remove Nth variable from list and compact list
  469. ------------------------------------------------------------------------- */
  470. void Variable::remove(int n)
  471. {
  472. delete [] names[n];
  473. if (style[n] == LOOP || style[n] == ULOOP) delete [] data[n][0];
  474. else for (int i = 0; i < num[n]; i++) delete [] data[n][i];
  475. delete [] data[n];
  476. for (int i = n+1; i < nvar; i++) {
  477. names[i-1] = names[i];
  478. style[i-1] = style[i];
  479. num[i-1] = num[i];
  480. which[i-1] = which[i];
  481. pad[i-1] = pad[i];
  482. data[i-1] = data[i];
  483. }
  484. nvar--;
  485. }
  486. /* ----------------------------------------------------------------------
  487. make space in arrays for new variable
  488. ------------------------------------------------------------------------- */
  489. void Variable::extend()
  490. {
  491. maxvar += VARDELTA;
  492. names = (char **)
  493. memory->srealloc(names,maxvar*sizeof(char *),"var:names");
  494. memory->grow(style,maxvar,"var:style");
  495. memory->grow(num,maxvar,"var:num");
  496. memory->grow(which,maxvar,"var:which");
  497. memory->grow(pad,maxvar,"var:pad");
  498. data = (char ***)
  499. memory->srealloc(data,maxvar*sizeof(char **),"var:data");
  500. }
  501. /* ----------------------------------------------------------------------
  502. copy narg strings from **from to **to, and allocate space for them
  503. ------------------------------------------------------------------------- */
  504. void Variable::copy(int narg, char **from, char **to)
  505. {
  506. int n;
  507. for (int i = 0; i < narg; i++) {
  508. n = strlen(from[i]) + 1;
  509. to[i] = new char[n];
  510. strcpy(to[i],from[i]);
  511. }
  512. }
  513. /* ----------------------------------------------------------------------
  514. recursive evaluation of a string str
  515. str is an equal-style or atom-style formula containing one or more items:
  516. number = 0.0, -5.45, 2.8e-4, ...
  517. constant = PI
  518. thermo keyword = ke, vol, atoms, ...
  519. math operation = (),-x,x+y,x-y,x*y,x/y,x^y,
  520. x==y,x!=y,x<y,x<=y,x>y,x>=y,x&&y,x||y,
  521. sqrt(x),exp(x),ln(x),log(x),
  522. sin(x),cos(x),tan(x),asin(x),atan2(y,x),...
  523. group function = count(group), mass(group), xcm(group,x), ...
  524. special function = sum(x),min(x), ...
  525. atom value = x[i], y[i], vx[i], ...
  526. atom vector = x, y, vx, ...
  527. compute = c_ID, c_ID[i], c_ID[i][j]
  528. fix = f_ID, f_ID[i], f_ID[i][j]
  529. variable = v_name, v_name[i]
  530. equal-style variables passes in tree = NULL:
  531. evaluate the formula, return result as a double
  532. atom-style variable passes in tree = non-NULL:
  533. parse the formula but do not evaluate it
  534. create a parse tree and return it
  535. ------------------------------------------------------------------------- */
  536. double Variable::evaluate(char *str, Tree **tree)
  537. {
  538. int op,opprevious;
  539. double value1,value2;
  540. char onechar;
  541. char *ptr;
  542. double argstack[MAXLEVEL];
  543. Tree *treestack[MAXLEVEL];
  544. int opstack[MAXLEVEL];
  545. int nargstack = 0;
  546. int ntreestack = 0;
  547. int nopstack = 0;
  548. int i = 0;
  549. int expect = ARG;
  550. while (1) {
  551. onechar = str[i];
  552. // whitespace: just skip
  553. if (isspace(onechar)) i++;
  554. // ----------------
  555. // parentheses: recursively evaluate contents of parens
  556. // ----------------
  557. else if (onechar == '(') {
  558. if (expect == OP) error->all("Invalid syntax in variable formula");
  559. expect = OP;
  560. char *contents;
  561. i = find_matching_paren(str,i,contents);
  562. i++;
  563. // evaluate contents and push on stack
  564. if (tree) {
  565. Tree *newtree;
  566. double tmp = evaluate(contents,&newtree);
  567. treestack[ntreestack++] = newtree;
  568. } else argstack[nargstack++] = evaluate(contents,NULL);
  569. delete [] contents;
  570. // ----------------
  571. // number: push value onto stack
  572. // ----------------
  573. } else if (isdigit(onechar) || onechar == '.') {
  574. if (expect == OP) error->all("Invalid syntax in variable formula");
  575. expect = OP;
  576. // istop = end of number, including scientific notation
  577. int istart = i;
  578. while (isdigit(str[i]) || str[i] == '.') i++;
  579. if (str[i] == 'e' || str[i] == 'E') {
  580. i++;
  581. if (str[i] == '+' || str[i] == '-') i++;
  582. while (isdigit(str[i])) i++;
  583. }
  584. int istop = i - 1;
  585. int n = istop - istart + 1;
  586. char *number = new char[n+1];
  587. strncpy(number,&str[istart],n);
  588. number[n] = '\0';
  589. if (tree) {
  590. Tree *newtree = new Tree();
  591. newtree->type = VALUE;
  592. newtree->value = atof(number);
  593. newtree->left = newtree->middle = newtree->right = NULL;
  594. treestack[ntreestack++] = newtree;
  595. } else argstack[nargstack++] = atof(number);
  596. delete [] number;
  597. // ----------------
  598. // letter: c_ID, c_ID[], c_ID[][], f_ID, f_ID[], f_ID[][],
  599. // v_name, v_name[], exp(), xcm(,), x, x[], PI, vol
  600. // ----------------
  601. } else if (isalpha(onechar)) {
  602. if (expect == OP) error->all("Invalid syntax in variable formula");
  603. expect = OP;
  604. // istop = end of word
  605. // word = all alphanumeric or underscore
  606. int istart = i;
  607. while (isalnum(str[i]) || str[i] == '_') i++;
  608. int istop = i-1;
  609. int n = istop - istart + 1;
  610. char *word = new char[n+1];
  611. strncpy(word,&str[istart],n);
  612. word[n] = '\0';
  613. // ----------------
  614. // compute
  615. // ----------------
  616. if (strncmp(word,"c_",2) == 0) {
  617. if (domain->box_exist == 0)
  618. error->all("Variable evaluation before simulation box is defined");
  619. n = strlen(word) - 2 + 1;
  620. char *id = new char[n];
  621. strcpy(id,&word[2]);
  622. int icompute = modify->find_compute(id);
  623. if (icompute < 0) error->all("Invalid compute ID in variable formula");
  624. Compute *compute = modify->compute[icompute];
  625. delete [] id;
  626. // parse zero or one or two trailing brackets
  627. // point i beyond last bracket
  628. // nbracket = # of bracket pairs
  629. // index1,index2 = int inside each bracket pair
  630. int nbracket,index1,index2;
  631. if (str[i] != '[') nbracket = 0;
  632. else {
  633. nbracket = 1;
  634. ptr = &str[i];
  635. index1 = int_between_brackets(ptr);
  636. i = ptr-str+1;
  637. if (str[i] == '[') {
  638. nbracket = 2;
  639. ptr = &str[i];
  640. index2 = int_between_brackets(ptr);
  641. i = ptr-str+1;
  642. }
  643. }
  644. // c_ID = scalar from global scalar
  645. if (nbracket == 0 && compute->scalar_flag) {
  646. if (update->whichflag == 0) {
  647. if (compute->invoked_scalar != update->ntimestep)
  648. error->all("Compute used in variable between runs "
  649. "is not current");
  650. } else if (!(compute->invoked_flag & INVOKED_SCALAR)) {
  651. compute->compute_scalar();
  652. compute->invoked_flag |= INVOKED_SCALAR;
  653. }
  654. value1 = compute->scalar;
  655. if (tree) {
  656. Tree *newtree = new Tree();
  657. newtree->type = VALUE;
  658. newtree->value = value1;
  659. newtree->left = newtree->middle = newtree->right = NULL;
  660. treestack[ntreestack++] = newtree;
  661. } else argstack[nargstack++] = value1;
  662. // c_ID[i] = scalar from global vector
  663. } else if (nbracket == 1 && compute->vector_flag) {
  664. if (index1 > compute->size_vector)
  665. error->all("Variable formula compute vector "
  666. "is accessed out-of-range");
  667. if (update->whichflag == 0) {
  668. if (compute->invoked_vector != update->ntimestep)
  669. error->all("Compute used in variable between runs "
  670. "is not current");
  671. } else if (!(compute->invoked_flag & INVOKED_VECTOR)) {
  672. compute->compute_vector();
  673. compute->invoked_flag |= INVOKED_VECTOR;
  674. }
  675. value1 = compute->vector[index1-1];
  676. if (tree) {
  677. Tree *newtree = new Tree();
  678. newtree->type = VALUE;
  679. newtree->value = value1;
  680. newtree->left = newtree->middle = newtree->right = NULL;
  681. treestack[ntreestack++] = newtree;
  682. } else argstack[nargstack++] = value1;
  683. // c_ID[i][j] = scalar from global array
  684. } else if (nbracket == 2 && compute->array_flag) {
  685. if (index1 > compute->size_array_rows)
  686. error->all("Variable formula compute array "
  687. "is accessed out-of-range");
  688. if (index2 > compute->size_array_cols)
  689. error->all("Variable formula compute array "
  690. "is accessed out-of-range");
  691. if (update->whichflag == 0) {
  692. if (compute->invoked_array != update->ntimestep)
  693. error->all("Compute used in variable between runs "
  694. "is not current");
  695. } else if (!(compute->invoked_flag & INVOKED_ARRAY)) {
  696. compute->compute_array();
  697. compute->invoked_flag |= INVOKED_ARRAY;
  698. }
  699. value1 = compute->array[index1-1][index2-1];
  700. if (tree) {
  701. Tree *newtree = new Tree();
  702. newtree->type = VALUE;
  703. newtree->value = value1;
  704. newtree->left = newtree->middle = newtree->right = NULL;
  705. treestack[ntreestack++] = newtree;
  706. } else argstack[nargstack++] = value1;
  707. // c_ID[i] = scalar from per-atom vector
  708. } else if (nbracket == 1 && compute->peratom_flag &&
  709. compute->size_peratom_cols == 0) {
  710. if (update->whichflag == 0) {
  711. if (compute->invoked_peratom != update->ntimestep)
  712. error->all("Compute used in variable between runs "
  713. "is not current");
  714. } else if (!(compute->invoked_flag & INVOKED_PERATOM)) {
  715. compute->compute_peratom();
  716. compute->invoked_flag |= INVOKED_PERATOM;
  717. }
  718. peratom2global(1,NULL,compute->vector_atom,1,index1,
  719. tree,treestack,ntreestack,argstack,nargstack);
  720. // c_ID[i][j] = scalar from per-atom array
  721. } else if (nbracket == 2 && compute->peratom_flag &&
  722. compute->size_peratom_cols > 0) {
  723. if (index2 > compute->size_peratom_cols)
  724. error->all("Variable formula compute array "
  725. "is accessed out-of-range");
  726. if (update->whichflag == 0) {
  727. if (compute->invoked_peratom != update->ntimestep)
  728. error->all("Compute used in variable between runs "
  729. "is not current");
  730. } else if (!(compute->invoked_flag & INVOKED_PERATOM)) {
  731. compute->compute_peratom();
  732. compute->invoked_flag |= INVOKED_PERATOM;
  733. }
  734. peratom2global(1,NULL,&compute->array_atom[0][index2-1],
  735. compute->size_peratom_cols,index1,
  736. tree,treestack,ntreestack,argstack,nargstack);
  737. // c_ID = vector from per-atom vector
  738. } else if (nbracket == 0 && compute->peratom_flag &&
  739. compute->size_peratom_cols == 0) {
  740. if (tree == NULL)
  741. error->all("Per-atom compute in equal-style variable formula");
  742. if (update->whichflag == 0) {
  743. if (compute->invoked_peratom != update->ntimestep)
  744. error->all("Compute used in variable between runs "
  745. "is not current");
  746. } else if (!(compute->invoked_flag & INVOKED_PERATOM)) {
  747. compute->compute_peratom();
  748. compute->invoked_flag |= INVOKED_PERATOM;
  749. }
  750. Tree *newtree = new Tree();
  751. newtree->type = ATOMARRAY;
  752. newtree->array = compute->vector_atom;
  753. newtree->nstride = 1;
  754. newtree->left = newtree->middle = newtree->right = NULL;
  755. treestack[ntreestack++] = newtree;
  756. // c_ID[i] = vector from per-atom array
  757. } else if (nbracket == 1 && compute->peratom_flag &&
  758. compute->size_peratom_cols > 0) {
  759. if (tree == NULL)
  760. error->all("Per-atom compute in equal-style variable formula");
  761. if (index1 > compute->size_peratom_cols)
  762. error->all("Variable formula compute array "
  763. "is accessed out-of-range");
  764. if (update->whichflag == 0) {
  765. if (compute->invoked_peratom != update->ntimestep)
  766. error->all("Compute used in variable between runs "
  767. "is not current");
  768. } else if (!(compute->invoked_flag & INVOKED_PERATOM)) {
  769. compute->compute_peratom();
  770. compute->invoked_flag |= INVOKED_PERATOM;
  771. }
  772. Tree *newtree = new Tree();
  773. newtree->type = ATOMARRAY;
  774. newtree->array = &compute->array_atom[0][index1-1];
  775. newtree->nstride = compute->size_peratom_cols;
  776. newtree->left = newtree->middle = newtree->right = NULL;
  777. treestack[ntreestack++] = newtree;
  778. } else error->all("Mismatched compute in variable formula");
  779. // ----------------
  780. // fix
  781. // ----------------
  782. } else if (strncmp(word,"f_",2) == 0) {
  783. if (domain->box_exist == 0)
  784. error->all("Variable evaluation before simulation box is defined");
  785. n = strlen(word) - 2 + 1;
  786. char *id = new char[n];
  787. strcpy(id,&word[2]);
  788. int ifix = modify->find_fix(id);
  789. if (ifix < 0) error->all("Invalid fix ID in variable formula");
  790. Fix *fix = modify->fix[ifix];
  791. delete [] id;
  792. // parse zero or one or two trailing brackets
  793. // point i beyond last bracket
  794. // nbracket = # of bracket pairs
  795. // index1,index2 = int inside each bracket pair
  796. int nbracket,index1,index2;
  797. if (str[i] != '[') nbracket = 0;
  798. else {
  799. nbracket = 1;
  800. ptr = &str[i];
  801. index1 = int_between_brackets(ptr);
  802. i = ptr-str+1;
  803. if (str[i] == '[') {
  804. nbracket = 2;
  805. ptr = &str[i];
  806. index2 = int_between_brackets(ptr);
  807. i = ptr-str+1;
  808. }
  809. }
  810. // f_ID = scalar from global scalar
  811. if (nbracket == 0 && fix->scalar_flag) {
  812. if (update->whichflag > 0 && update->ntimestep % fix->global_freq)
  813. error->all("Fix in variable not computed at compatible time");
  814. value1 = fix->compute_scalar();
  815. if (tree) {
  816. Tree *newtree = new Tree();
  817. newtree->type = VALUE;
  818. newtree->value = value1;
  819. newtree->left = newtree->middle = newtree->right = NULL;
  820. treestack[ntreestack++] = newtree;
  821. } else argstack[nargstack++] = value1;
  822. // f_ID[i] = scalar from global vector
  823. } else if (nbracket == 1 && fix->vector_flag) {
  824. if (index1 > fix->size_vector)
  825. error->all("Variable formula fix vector is accessed out-of-range");
  826. if (update->whichflag > 0 && update->ntimestep % fix->global_freq)
  827. error->all("Fix in variable not computed at compatible time");
  828. value1 = fix->compute_vector(index1-1);
  829. if (tree) {
  830. Tree *newtree = new Tree();
  831. newtree->type = VALUE;
  832. newtree->value = value1;
  833. newtree->left = newtree->middle = newtree->right = NULL;
  834. treestack[ntreestack++] = newtree;
  835. } else argstack[nargstack++] = value1;
  836. // f_ID[i][j] = scalar from global array
  837. } else if (nbracket == 2 && fix->array_flag) {
  838. if (index1 > fix->size_array_rows)
  839. error->all("Variable formula fix array is accessed out-of-range");
  840. if (index2 > fix->size_array_cols)
  841. error->all("Variable formula fix array is accessed out-of-range");
  842. if (update->whichflag > 0 && update->ntimestep % fix->global_freq)
  843. error->all("Fix in variable not computed at compatible time");
  844. value1 = fix->compute_array(index1-1,index2-1);
  845. if (tree) {
  846. Tree *newtree = new Tree();
  847. newtree->type = VALUE;
  848. newtree->value = value1;
  849. newtree->left = newtree->middle = newtree->right = NULL;
  850. treestack[ntreestack++] = newtree;
  851. } else argstack[nargstack++] = value1;
  852. // f_ID[i] = scalar from per-atom vector
  853. } else if (nbracket == 1 && fix->peratom_flag &&
  854. fix->size_peratom_cols == 0) {
  855. if (update->whichflag > 0 &&
  856. update->ntimestep % fix->peratom_freq)
  857. error->all("Fix in variable not computed at compatible time");
  858. peratom2global(1,NULL,fix->vector_atom,1,index1,
  859. tree,treestack,ntreestack,argstack,nargstack);
  860. // f_ID[i][j] = scalar from per-atom array
  861. } else if (nbracket == 2 && fix->peratom_flag &&
  862. fix->size_peratom_cols > 0) {
  863. if (index2 > fix->size_peratom_cols)
  864. error->all("Variable formula fix array is accessed out-of-range");
  865. if (update->whichflag > 0 &&
  866. update->ntimestep % fix->peratom_freq)
  867. error->all("Fix in variable not computed at compatible time");
  868. peratom2global(1,NULL,&fix->array_atom[0][index2-1],
  869. fix->size_peratom_cols,index1,
  870. tree,treestack,ntreestack,argstack,nargstack);
  871. // f_ID = vector from per-atom vector
  872. } else if (nbracket == 0 && fix->peratom_flag &&
  873. fix->size_peratom_cols == 0) {
  874. if (tree == NULL)
  875. error->all("Per-atom fix in equal-style variable formula");
  876. if (update->whichflag > 0 &&
  877. update->ntimestep % fix->peratom_freq)
  878. error->all("Fix in variable not computed at compatible time");
  879. Tree *newtree = new Tree();
  880. newtree->type = ATOMARRAY;
  881. newtree->array = fix->vector_atom;
  882. newtree->nstride = 1;
  883. newtree->left = newtree->middle = newtree->right = NULL;
  884. treestack[ntreestack++] = newtree;
  885. // f_ID[i] = vector from per-atom array
  886. } else if (nbracket == 1 && fix->peratom_flag &&
  887. fix->size_peratom_cols > 0) {
  888. if (tree == NULL)
  889. error->all("Per-atom fix in equal-style variable formula");
  890. if (index1 > fix->size_peratom_cols)
  891. error->all("Variable formula fix array is accessed out-of-range");
  892. if (update->whichflag > 0 &&
  893. update->ntimestep % fix->peratom_freq)
  894. error->all("Fix in variable not computed at compatible time");
  895. Tree *newtree = new Tree();
  896. newtree->type = ATOMARRAY;
  897. newtree->array = &fix->array_atom[0][index1-1];
  898. newtree->nstride = fix->size_peratom_cols;
  899. newtree->left = newtree->middle = newtree->right = NULL;
  900. treestack[ntreestack++] = newtree;
  901. } else error->all("Mismatched fix in variable formula");
  902. // ----------------
  903. // variable
  904. // ----------------
  905. } else if (strncmp(word,"v_",2) == 0) {
  906. n = strlen(word) - 2 + 1;
  907. char *id = new char[n];
  908. strcpy(id,&word[2]);
  909. int ivar = find(id);
  910. if (ivar < 0) error->all("Invalid variable name in variable formula");
  911. // parse zero or one trailing brackets
  912. // point i beyond last bracket
  913. // nbracket = # of bracket pairs
  914. // index = int inside bracket
  915. int nbracket,index;
  916. if (str[i] != '[') nbracket = 0;
  917. else {
  918. nbracket = 1;
  919. ptr = &str[i];
  920. index = int_between_brackets(ptr);
  921. i = ptr-str+1;
  922. }
  923. // v_name = scalar from non atom-style global scalar
  924. if (nbracket == 0 && style[ivar] != ATOM) {
  925. char *var = retrieve(id);
  926. if (var == NULL)
  927. error->all("Invalid variable evaluation in variable formula");
  928. if (tree) {
  929. Tree *newtree = new Tree();
  930. newtree->type = VALUE;
  931. newtree->value = atof(var);
  932. newtree->left = newtree->middle = newtree->right = NULL;
  933. treestack[ntreestack++] = newtree;
  934. } else argstack[nargstack++] = atof(var);
  935. // v_name = vector from atom-style per-atom vector
  936. } else if (nbracket == 0 && style[ivar] == ATOM) {
  937. if (tree == NULL)
  938. error->all("Atom-style variable in equal-style variable formula");
  939. Tree *newtree;
  940. double tmp = evaluate(data[ivar][0],&newtree);
  941. treestack[ntreestack++] = newtree;
  942. // v_name[N] = scalar from atom-style per-atom vector
  943. // compute the per-atom variable in result
  944. // use peratom2global to extract single value from result
  945. } else if (nbracket && style[ivar] == ATOM) {
  946. double *result;
  947. memory->create(result,atom->nlocal,"variable:result");
  948. compute_atom(ivar,0,result,1,0);
  949. peratom2global(1,NULL,result,1,index,
  950. tree,treestack,ntreestack,argstack,nargstack);
  951. memory->destroy(result);
  952. } else error->all("Mismatched variable in variable formula");
  953. delete [] id;
  954. // ----------------
  955. // math/group/special function or atom value/vector or
  956. // constant or thermo keyword
  957. // ----------------
  958. } else {
  959. // ----------------
  960. // math or group or special function
  961. // ----------------
  962. if (str[i] == '(') {
  963. char *contents;
  964. i = find_matching_paren(str,i,contents);
  965. i++;
  966. if (math_function(word,contents,tree,
  967. treestack,ntreestack,argstack,nargstack));
  968. else if (group_function(word,contents,tree,
  969. treestack,ntreestack,argstack,nargstack));
  970. else if (special_function(word,contents,tree,
  971. treestack,ntreestack,argstack,nargstack));
  972. else error->all("Invalid math/group/special function "
  973. "in variable formula");
  974. delete [] contents;
  975. // ----------------
  976. // atom value
  977. // ----------------
  978. } else if (str[i] == '[') {
  979. if (domain->box_exist == 0)
  980. error->all("Variable evaluation before simulation box is defined");
  981. ptr = &str[i];
  982. int id = int_between_brackets(ptr);
  983. i = ptr-str+1;
  984. peratom2global(0,word,NULL,0,id,
  985. tree,treestack,ntreestack,argstack,nargstack);
  986. // ----------------
  987. // atom vector
  988. // ----------------
  989. } else if (is_atom_vector(word)) {
  990. if (domain->box_exist == 0)
  991. error->all("Variable evaluation before simulation box is defined");
  992. atom_vector(word,tree,treestack,ntreestack);
  993. // ----------------
  994. // constant
  995. // ----------------
  996. } else if (is_constant(word)) {
  997. value1 = constant(word);
  998. if (tree) {
  999. Tree *newtree = new Tree();
  1000. newtree->type = VALUE;
  1001. newtree->value = value1;
  1002. newtree->left = newtree->middle = newtree->right = NULL;
  1003. treestack[ntreestack++] = newtree;
  1004. } else argstack[nargstack++] = value1;
  1005. // ----------------
  1006. // thermo keyword
  1007. // ----------------
  1008. } else {
  1009. if (domain->box_exist == 0)
  1010. error->all("Variable evaluation before simulation box is defined");
  1011. int flag = output->thermo->evaluate_keyword(word,&value1);
  1012. if (flag) error->all("Invalid thermo keyword in variable formula");
  1013. if (tree) {
  1014. Tree *newtree = new Tree();
  1015. newtree->type = VALUE;
  1016. newtree->value = value1;
  1017. newtree->left = newtree->middle = newtree->right = NULL;
  1018. treestack[ntreestack++] = newtree;
  1019. } else argstack[nargstack++] = value1;
  1020. }
  1021. }
  1022. delete [] word;
  1023. // ----------------
  1024. // math operator, including end-of-string
  1025. // ----------------
  1026. } else if (strchr("+-*/^<>=!&|\0",onechar)) {
  1027. if (onechar == '+') op = ADD;
  1028. else if (onechar == '-') op = SUBTRACT;
  1029. else if (onechar == '*') op = MULTIPLY;
  1030. else if (onechar == '/') op = DIVIDE;
  1031. else if (onechar == '^') op = CARAT;
  1032. else if (onechar == '=') {
  1033. if (str[i+1] != '=') error->all("Invalid syntax in variable formula");
  1034. op = EQ;
  1035. i++;
  1036. } else if (onechar == '!') {
  1037. if (str[i+1] == '=') {
  1038. op = NE;
  1039. i++;
  1040. } else op = NOT;
  1041. } else if (onechar == '<') {
  1042. if (str[i+1] != '=') op = LT;
  1043. else {
  1044. op = LE;
  1045. i++;
  1046. }
  1047. } else if (onechar == '>') {
  1048. if (str[i+1] != '=') op = GT;
  1049. else {
  1050. op = GE;
  1051. i++;
  1052. }
  1053. } else if (onechar == '&') {
  1054. if (str[i+1] != '&') error->all("Invalid syntax in variable formula");
  1055. op = AND;
  1056. i++;
  1057. } else if (onechar == '|') {
  1058. if (str[i+1] != '|') error->all("Invalid syntax in variable formula");
  1059. op = OR;
  1060. i++;
  1061. } else op = DONE;
  1062. i++;
  1063. if (op == SUBTRACT && expect == ARG) {
  1064. opstack[nopstack++] = UNARY;
  1065. continue;
  1066. }
  1067. if (op == NOT && expect == ARG) {
  1068. opstack[nopstack++] = op;
  1069. continue;
  1070. }
  1071. if (expect == ARG) error->all("Invalid syntax in variable formula");
  1072. expect = ARG;
  1073. // evaluate stack as deep as possible while respecting precedence
  1074. // before pushing current op onto stack
  1075. while (nopstack && precedence[opstack[nopstack-1]] >= precedence[op]) {
  1076. opprevious = opstack[--nopstack];
  1077. if (tree) {
  1078. Tree *newtree = new Tree();
  1079. newtree->type = opprevious;
  1080. if (opprevious == UNARY) {
  1081. newtree->left = treestack[--ntreestack];
  1082. newtree->middle = newtree->right = NULL;
  1083. } else {
  1084. newtree->right = treestack[--ntreestack];
  1085. newtree->middle = NULL;
  1086. newtree->left = treestack[--ntreestack];
  1087. }
  1088. treestack[ntreestack++] = newtree;
  1089. } else {
  1090. value2 = argstack[--nargstack];
  1091. if (opprevious != UNARY && opprevious != NOT)
  1092. value1 = argstack[--nargstack];
  1093. if (opprevious == ADD)
  1094. argstack[nargstack++] = value1 + value2;
  1095. else if (opprevious == SUBTRACT)
  1096. argstack[nargstack++] = value1 - value2;
  1097. else if (opprevious == MULTIPLY)
  1098. argstack[nargstack++] = value1 * value2;
  1099. else if (opprevious == DIVIDE) {
  1100. if (value2 == 0.0) error->all("Divide by 0 in variable formula");
  1101. argstack[nargstack++] = value1 / value2;
  1102. } else if (opprevious == CARAT) {
  1103. if (value2 == 0.0) error->all("Power by 0 in variable formula");
  1104. argstack[nargstack++] = pow(value1,value2);
  1105. } else if (opprevious == UNARY) {
  1106. argstack[nargstack++] = -value2;
  1107. } else if (opprevious == NOT) {
  1108. if (value2 == 0.0) argstack[nargstack++] = 1.0;
  1109. else argstack[nargstack++] = 0.0;
  1110. } else if (opprevious == EQ) {
  1111. if (value1 == value2) argstack[nargstack++] = 1.0;
  1112. else argstack[nargstack++] = 0.0;
  1113. } else if (opprevious == NE) {
  1114. if (value1 != value2) argstack[nargstack++] = 1.0;
  1115. else argstack[nargstack++] = 0.0;
  1116. } else if (opprevious == LT) {
  1117. if (value1 < value2) argstack[nargstack++] = 1.0;
  1118. else argstack[nargstack++] = 0.0;
  1119. } else if (opprevious == LE) {
  1120. if (value1 <= value2) argstack[nargstack++] = 1.0;
  1121. else argstack[nargstack++] = 0.0;
  1122. } else if (opprevious == GT) {
  1123. if (value1 > value2) argstack[nargstack++] = 1.0;
  1124. else argstack[nargstack++] = 0.0;
  1125. } else if (opprevious == GE) {
  1126. if (value1 >= value2) argstack[nargstack++] = 1.0;
  1127. else argstack[nargstack++] = 0.0;
  1128. } else if (opprevious == AND) {
  1129. if (value1 != 0.0 && value2 != 0.0) argstack[nargstack++] = 1.0;
  1130. else argstack[nargstack++] = 0.0;
  1131. } else if (opprevious == OR) {
  1132. if (value1 != 0.0 || value2 != 0.0) argstack[nargstack++] = 1.0;
  1133. else argstack[nargstack++] = 0.0;
  1134. }
  1135. }
  1136. }
  1137. // if end-of-string, break out of entire formula evaluation loop
  1138. if (op == DONE) break;
  1139. // push current operation onto stack
  1140. opstack[nopstack++] = op;
  1141. } else error->all("Invalid syntax in variable formula");
  1142. }
  1143. if (nopstack) error->all("Invalid syntax in variable formula");
  1144. // for atom-style variable, return remaining tree
  1145. // for equal-style variable, return remaining arg
  1146. if (tree) {
  1147. if (ntreestack != 1) error->all("Invalid syntax in variable formula");
  1148. *tree = treestack[0];
  1149. return 0.0;
  1150. } else {
  1151. if (nargstack != 1) error->all("Invalid syntax in variable formula");
  1152. return argstack[0];
  1153. }
  1154. }
  1155. /* ----------------------------------------------------------------------
  1156. one-time collapse of an atom-style variable parse tree
  1157. tree was created by one-time parsing of formula string via evaulate()
  1158. only keep tree nodes that depend on ATOMARRAY, TYPEARRAY, INTARRAY
  1159. remainder is converted to single VALUE
  1160. this enables optimal eval_tree loop over atoms
  1161. customize by adding a function:
  1162. sqrt(),exp(),ln(),log(),sin(),cos(),tan(),asin(),acos(),atan(),
  1163. atan2(y,x),random(x,y,z),normal(x,y,z),ceil(),floor(),round(),
  1164. ramp(x,y),stagger(x,y),logfreq(x,y,z),
  1165. vdisplace(x,y),swiggle(x,y,z),cwiggle(x,y,z),
  1166. gmask(x),rmask(x),grmask(x,y)
  1167. ---------------------------------------------------------------------- */
  1168. double Variable::collapse_tree(Tree *tree)
  1169. {
  1170. double arg1,arg2,arg3;
  1171. if (tree->type == VALUE) return tree->value;
  1172. if (tree->type == ATOMARRAY) return 0.0;
  1173. if (tree->type == TYPEARRAY) return 0.0;
  1174. if (tree->type == INTARRAY) return 0.0;
  1175. if (tree->type == ADD) {
  1176. arg1 = collapse_tree(tree->left);
  1177. arg2 = collapse_tree(tree->right);
  1178. if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
  1179. tree->type = VALUE;
  1180. tree->value = arg1 + arg2;
  1181. return tree->value;
  1182. }
  1183. if (tree->type == SUBTRACT) {
  1184. arg1 = collapse_tree(tree->left);
  1185. arg2 = collapse_tree(tree->right);
  1186. if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
  1187. tree->type = VALUE;
  1188. tree->value = arg1 - arg2;
  1189. return tree->value;
  1190. }
  1191. if (tree->type == MULTIPLY) {
  1192. arg1 = collapse_tree(tree->left);
  1193. arg2 = collapse_tree(tree->right);
  1194. if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
  1195. tree->type = VALUE;
  1196. tree->value = arg1 * arg2;
  1197. return tree->value;
  1198. }
  1199. if (tree->type == DIVIDE) {
  1200. arg1 = collapse_tree(tree->left);
  1201. arg2 = collapse_tree(tree->right);
  1202. if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
  1203. tree->type = VALUE;
  1204. if (arg2 == 0.0) error->one("Divide by 0 in variable formula");
  1205. tree->value = arg1 / arg2;
  1206. return tree->value;
  1207. }
  1208. if (tree->type == CARAT) {
  1209. arg1 = collapse_tree(tree->left);
  1210. arg2 = collapse_tree(tree->right);
  1211. if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
  1212. tree->type = VALUE;
  1213. if (arg2 == 0.0) error->one("Power by 0 in variable formula");
  1214. tree->value = pow(arg1,arg2);
  1215. return tree->value;
  1216. }
  1217. if (tree->type == UNARY) {
  1218. arg1 = collapse_tree(tree->left);
  1219. if (tree->left->type != VALUE) return 0.0;
  1220. tree->type = VALUE;
  1221. tree->value = -arg1;
  1222. return tree->value;
  1223. }
  1224. if (tree->type == NOT) {
  1225. arg1 = collapse_tree(tree->left);
  1226. if (tree->left->type != VALUE) return 0.0;
  1227. tree->type = VALUE;
  1228. if (arg1 == 0.0) tree->value = 1.0;
  1229. else tree->value = 0.0;
  1230. return tree->value;
  1231. }
  1232. if (tree->type == EQ) {
  1233. arg1 = collapse_tree(tree->left);
  1234. arg2 = collapse_tree(tree->right);
  1235. if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
  1236. tree->type = VALUE;
  1237. if (arg1 == arg2) tree->value = 1.0;
  1238. else tree->value = 0.0;
  1239. return tree->value;
  1240. }
  1241. if (tree->type == NE) {
  1242. arg1 = collapse_tree(tree->left);
  1243. arg2 = collapse_tree(tree->right);
  1244. if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
  1245. tree->type = VALUE;
  1246. if (arg1 != arg2) tree->value = 1.0;
  1247. else tree->value = 0.0;
  1248. return tree->value;
  1249. }
  1250. if (tree->type == LT) {
  1251. arg1 = collapse_tree(tree->left);
  1252. arg2 = collapse_tree(tree->right);
  1253. if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
  1254. tree->type = VALUE;
  1255. if (arg1 < arg2) tree->value = 1.0;
  1256. else tree->value = 0.0;
  1257. return tree->value;
  1258. }
  1259. if (tree->type == LE) {
  1260. arg1 = collapse_tree(tree->left);
  1261. arg2 = collapse_tree(tree->right);
  1262. if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
  1263. tree->type = VALUE;
  1264. if (arg1 <= arg2) tree->value = 1.0;
  1265. else tree->value = 0.0;
  1266. return tree->value;
  1267. }
  1268. if (tree->type == GT) {
  1269. arg1 = collapse_tree(tree->left);
  1270. arg2 = collapse_tree(tree->right);
  1271. if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
  1272. tree->type = VALUE;
  1273. if (arg1 > arg2) tree->value = 1.0;
  1274. else tree->value = 0.0;
  1275. return tree->value;
  1276. }
  1277. if (tree->type == GE) {
  1278. arg1 = collapse_tree(tree->left);
  1279. arg2 = collapse_tree(tree->right);
  1280. if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
  1281. tree->type = VALUE;
  1282. if (arg1 >= arg2) tree->value = 1.0;
  1283. else tree->value = 0.0;
  1284. return tree->value;
  1285. }
  1286. if (tree->type == AND) {
  1287. arg1 = collapse_tree(tree->left);
  1288. arg2 = collapse_tree(tree->right);
  1289. if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
  1290. tree->type = VALUE;
  1291. if (arg1 != 0.0 && arg2 != 0.0) tree->value = 1.0;
  1292. else tree->value = 0.0;
  1293. return tree->value;
  1294. }
  1295. if (tree->type == OR) {
  1296. arg1 = collapse_tree(tree->left);
  1297. arg2 = collapse_tree(tree->right);
  1298. if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
  1299. tree->type = VALUE;
  1300. if (arg1 != 0.0 || arg2 != 0.0) tree->value = 1.0;
  1301. else tree->value = 0.0;
  1302. return tree->value;
  1303. }
  1304. if (tree->type == SQRT) {
  1305. arg1 = collapse_tree(tree->left);
  1306. if (tree->left->type != VALUE) return 0.0;
  1307. tree->type = VALUE;
  1308. if (arg1 < 0.0) error->one("Sqrt of negative value in variable formula");
  1309. tree->value = sqrt(arg1);
  1310. return tree->value;
  1311. }
  1312. if (tree->type == EXP) {
  1313. arg1 = collapse_tree(tree->left);
  1314. if (tree->left->type != VALUE) return 0.0;
  1315. tree->type = VALUE;
  1316. tree->value = exp(arg1);
  1317. return tree->value;
  1318. }
  1319. if (tree->type == LN) {
  1320. arg1 = collapse_tree(tree->left);
  1321. if (tree->left->type != VALUE) return 0.0;
  1322. tree->type = VALUE;
  1323. if (arg1 <= 0.0)
  1324. error->one("Log of zero/negative value in variable formula");
  1325. tree->value = log(arg1);
  1326. return tree->value;
  1327. }
  1328. if (tree->type == LOG) {
  1329. arg1 = collapse_tree(tree->left);
  1330. if (tree->left->type != VALUE) return 0.0;
  1331. tree->type = VALUE;
  1332. if (arg1 <= 0.0)
  1333. error->one("Log of zero/negative value in variable formula");
  1334. tree->value = log10(arg1);
  1335. return tree->value;
  1336. }
  1337. if (tree->type == SIN) {
  1338. arg1 = collapse_tree(tree->left);
  1339. if (tree->left->type != VALUE) return 0.0;
  1340. tree->type = VALUE;
  1341. tree->value = sin(arg1);
  1342. return tree->value;
  1343. }
  1344. if (tree->type == COS) {
  1345. arg1 = collapse_tree(tree->left);
  1346. if (tree->left->type != VALUE) return 0.0;
  1347. tree->type = VALUE;
  1348. tree->value = cos(arg1);
  1349. return tree->value;
  1350. }
  1351. if (tree->type == TAN) {
  1352. arg1 = collapse_tree(tree->left);
  1353. if (tree->left->type != VALUE) return 0.0;
  1354. tree->type = VALUE;
  1355. tree->value = tan(arg1);
  1356. return tree->value;
  1357. }
  1358. if (tree->type == ASIN) {
  1359. arg1 = collapse_tree(tree->left);
  1360. if (tree->left->type != VALUE) return 0.0;
  1361. tree->type = VALUE;
  1362. if (arg1 < -1.0 || arg1 > 1.0)
  1363. error->one("Arcsin of invalid value in variable formula");
  1364. tree->value = asin(arg1);
  1365. return tree->value;
  1366. }
  1367. if (tree->type == ACOS) {
  1368. arg1 = collapse_tree(tree->left);
  1369. if (tree->left->type != VALUE) return 0.0;

Large files files are truncated, but you can click here to view the full file