PageRenderTime 38ms CodeModel.GetById 19ms 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
  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;
  1370. tree->type = VALUE;
  1371. if (arg1 < -1.0 || arg1 > 1.0)
  1372. error->one("Arccos of invalid value in variable formula");
  1373. tree->value = acos(arg1);
  1374. return tree->value;
  1375. }
  1376. if (tree->type == ATAN) {
  1377. arg1 = collapse_tree(tree->left);
  1378. if (tree->left->type != VALUE) return 0.0;
  1379. tree->type = VALUE;
  1380. tree->value = atan(arg1);
  1381. return tree->value;
  1382. }
  1383. if (tree->type == ATAN2) {
  1384. arg1 = collapse_tree(tree->left);
  1385. arg2 = collapse_tree(tree->right);
  1386. if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
  1387. tree->type = VALUE;
  1388. tree->value = atan2(arg1,arg2);
  1389. return tree->value;
  1390. }
  1391. // random() or normal() do not become a single collapsed value
  1392. if (tree->type == RANDOM) {
  1393. double lower = collapse_tree(tree->left);
  1394. double upper = collapse_tree(tree->middle);
  1395. if (randomatom == NULL) {
  1396. int seed = static_cast<int> (collapse_tree(tree->right));
  1397. if (seed <= 0) error->one("Invalid math function in variable formula");
  1398. randomatom = new RanMars(lmp,seed+me);
  1399. }
  1400. return 0.0;
  1401. }
  1402. if (tree->type == NORMAL) {
  1403. double mu = collapse_tree(tree->left);
  1404. double sigma = collapse_tree(tree->middle);
  1405. if (sigma < 0.0) error->one("Invalid math function in variable formula");
  1406. if (randomatom == NULL) {
  1407. int seed = static_cast<int> (collapse_tree(tree->right));
  1408. if (seed <= 0) error->one("Invalid math function in variable formula");
  1409. randomatom = new RanMars(lmp,seed+me);
  1410. }
  1411. return 0.0;
  1412. }
  1413. if (tree->type == CEIL) {
  1414. arg1 = collapse_tree(tree->left);
  1415. if (tree->left->type != VALUE) return 0.0;
  1416. tree->type = VALUE;
  1417. tree->value = ceil(arg1);
  1418. return tree->value;
  1419. }
  1420. if (tree->type == FLOOR) {
  1421. arg1 = collapse_tree(tree->left);
  1422. if (tree->left->type != VALUE) return 0.0;
  1423. tree->type = VALUE;
  1424. tree->value = floor(arg1);
  1425. return tree->value;
  1426. }
  1427. if (tree->type == ROUND) {
  1428. arg1 = collapse_tree(tree->left);
  1429. if (tree->left->type != VALUE) return 0.0;
  1430. tree->type = VALUE;
  1431. tree->value = MYROUND(arg1);
  1432. return tree->value;
  1433. }
  1434. if (tree->type == RAMP) {
  1435. arg1 = collapse_tree(tree->left);
  1436. arg2 = collapse_tree(tree->right);
  1437. if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
  1438. tree->type = VALUE;
  1439. double delta = update->ntimestep - update->beginstep;
  1440. delta /= update->endstep - update->beginstep;
  1441. tree->value = arg1 + delta*(arg2-arg1);
  1442. return tree->value;
  1443. }
  1444. if (tree->type == STAGGER) {
  1445. int ivalue1 = static_cast<int> (collapse_tree(tree->left));
  1446. int ivalue2 = static_cast<int> (collapse_tree(tree->right));
  1447. if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
  1448. tree->type = VALUE;
  1449. if (ivalue1 <= 0 || ivalue2 <= 0 || ivalue1 <= ivalue2)
  1450. error->one("Invalid math function in variable formula");
  1451. int lower = update->ntimestep/ivalue1 * ivalue1;
  1452. int delta = update->ntimestep - lower;
  1453. if (delta < ivalue2) tree->value = lower+ivalue2;
  1454. else tree->value = lower+ivalue1;
  1455. return tree->value;
  1456. }
  1457. if (tree->type == LOGFREQ) {
  1458. int ivalue1 = static_cast<int> (collapse_tree(tree->left));
  1459. int ivalue2 = static_cast<int> (collapse_tree(tree->middle));
  1460. int ivalue3 = static_cast<int> (collapse_tree(tree->right));
  1461. if (tree->left->type != VALUE || tree->middle->type != VALUE ||
  1462. tree->right->type != VALUE) return 0.0;
  1463. tree->type = VALUE;
  1464. if (ivalue1 <= 0 || ivalue2 <= 0 || ivalue3 <= 0 || ivalue2 >= ivalue3)
  1465. error->one("Invalid math function in variable formula");
  1466. if (update->ntimestep < ivalue1) tree->value = ivalue1;
  1467. else {
  1468. int lower = ivalue1;
  1469. while (update->ntimestep >= ivalue3*lower) lower *= ivalue3;
  1470. int multiple = update->ntimestep/lower;
  1471. if (multiple < ivalue2) tree->value = (multiple+1)*lower;
  1472. else tree->value = lower*ivalue3;
  1473. }
  1474. return tree->value;
  1475. }
  1476. if (tree->type == VDISPLACE) {
  1477. double arg1 = collapse_tree(tree->left);
  1478. double arg2 = collapse_tree(tree->right);
  1479. if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
  1480. tree->type = VALUE;
  1481. double delta = update->ntimestep - update->beginstep;
  1482. tree->value = arg1 + arg2*delta*update->dt;
  1483. return tree->value;
  1484. }
  1485. if (tree->type == SWIGGLE) {
  1486. double arg1 = collapse_tree(tree->left);
  1487. double arg2 = collapse_tree(tree->middle);
  1488. double arg3 = collapse_tree(tree->right);
  1489. if (tree->left->type != VALUE || tree->middle->type != VALUE ||
  1490. tree->right->type != VALUE) return 0.0;
  1491. tree->type = VALUE;
  1492. if (arg3 == 0.0) error->one("Invalid math function in variable formula");
  1493. double delta = update->ntimestep - update->beginstep;
  1494. double omega = 2.0*PI/arg3;
  1495. tree->value = arg1 + arg2*sin(omega*delta*update->dt);
  1496. return tree->value;
  1497. }
  1498. if (tree->type == CWIGGLE) {
  1499. double arg1 = collapse_tree(tree->left);
  1500. double arg2 = collapse_tree(tree->middle);
  1501. double arg3 = collapse_tree(tree->right);
  1502. if (tree->left->type != VALUE || tree->middle->type != VALUE ||
  1503. tree->right->type != VALUE) return 0.0;
  1504. tree->type = VALUE;
  1505. if (arg3 == 0.0) error->one("Invalid math function in variable formula");
  1506. double delta = update->ntimestep - update->beginstep;
  1507. double omega = 2.0*PI/arg3;
  1508. tree->value = arg1 + arg2*(1.0-cos(omega*delta*update->dt));
  1509. return tree->value;
  1510. }
  1511. // mask functions do not become a single collapsed value
  1512. if (tree->type == GMASK) return 0.0;
  1513. if (tree->type == RMASK) return 0.0;
  1514. if (tree->type == GRMASK) return 0.0;
  1515. return 0.0;
  1516. }
  1517. /* ----------------------------------------------------------------------
  1518. evaluate an atom-style variable parse tree for atom I
  1519. tree was created by one-time parsing of formula string via evaulate()
  1520. customize by adding a function:
  1521. sqrt(),exp(),ln(),log(),sin(),cos(),tan(),asin(),acos(),atan(),
  1522. atan2(y,x),random(x,y,z),normal(x,y,z),ceil(),floor(),round(),
  1523. ramp(x,y),stagger(x,y),logfreq(x,y,z),
  1524. vdisplace(x,y),swiggle(x,y,z),cwiggle(x,y,z),
  1525. gmask(x),rmask(x),grmask(x,y)
  1526. ---------------------------------------------------------------------- */
  1527. double Variable::eval_tree(Tree *tree, int i)
  1528. {
  1529. double arg,arg1,arg2,arg3;
  1530. if (tree->type == VALUE) return tree->value;
  1531. if (tree->type == ATOMARRAY) return tree->array[i*tree->nstride];
  1532. if (tree->type == TYPEARRAY) return tree->array[atom->type[i]];
  1533. if (tree->type == INTARRAY) return (double) tree->iarray[i*tree->nstride];
  1534. if (tree->type == ADD)
  1535. return eval_tree(tree->left,i) + eval_tree(tree->right,i);
  1536. if (tree->type == SUBTRACT)
  1537. return eval_tree(tree->left,i) - eval_tree(tree->right,i);
  1538. if (tree->type == MULTIPLY)
  1539. return eval_tree(tree->left,i) * eval_tree(tree->right,i);
  1540. if (tree->type == DIVIDE) {
  1541. double denom = eval_tree(tree->right,i);
  1542. if (denom == 0.0) error->one("Divide by 0 in variable formula");
  1543. return eval_tree(tree->left,i) / denom;
  1544. }
  1545. if (tree->type == CARAT) {
  1546. double exponent = eval_tree(tree->right,i);
  1547. if (exponent == 0.0) error->one("Power by 0 in variable formula");
  1548. return pow(eval_tree(tree->left,i),exponent);
  1549. }
  1550. if (tree->type == UNARY) return -eval_tree(tree->left,i);
  1551. if (tree->type == NOT) {
  1552. if (eval_tree(tree->left,i) == 0.0) return 1.0;
  1553. else return 0.0;
  1554. }
  1555. if (tree->type == EQ) {
  1556. if (eval_tree(tree->left,i) == eval_tree(tree->right,i)) return 1.0;
  1557. else return 0.0;
  1558. }
  1559. if (tree->type == NE) {
  1560. if (eval_tree(tree->left,i) != eval_tree(tree->right,i)) return 1.0;
  1561. else return 0.0;
  1562. }
  1563. if (tree->type == LT) {
  1564. if (eval_tree(tree->left,i) < eval_tree(tree->right,i)) return 1.0;
  1565. else return 0.0;
  1566. }
  1567. if (tree->type == LE) {
  1568. if (eval_tree(tree->left,i) <= eval_tree(tree->right,i)) return 1.0;
  1569. else return 0.0;
  1570. }
  1571. if (tree->type == GT) {
  1572. if (eval_tree(tree->left,i) > eval_tree(tree->right,i)) return 1.0;
  1573. else return 0.0;
  1574. }
  1575. if (tree->type == GE) {
  1576. if (eval_tree(tree->left,i) >= eval_tree(tree->right,i)) return 1.0;
  1577. else return 0.0;
  1578. }
  1579. if (tree->type == AND) {
  1580. if (eval_tree(tree->left,i) != 0.0 && eval_tree(tree->right,i) != 0.0)
  1581. return 1.0;
  1582. else return 0.0;
  1583. }
  1584. if (tree->type == OR) {
  1585. if (eval_tree(tree->left,i) != 0.0 || eval_tree(tree->right,i) != 0.0)
  1586. return 1.0;
  1587. else return 0.0;
  1588. }
  1589. if (tree->type == SQRT) {
  1590. arg1 = eval_tree(tree->left,i);
  1591. if (arg1 < 0.0) error->one("Sqrt of negative value in variable formula");
  1592. return sqrt(arg1);
  1593. }
  1594. if (tree->type == EXP)
  1595. return exp(eval_tree(tree->left,i));
  1596. if (tree->type == LN) {
  1597. arg1 = eval_tree(tree->left,i);
  1598. if (arg1 <= 0.0)
  1599. error->one("Log of zero/negative value in variable formula");
  1600. return log(arg1);
  1601. }
  1602. if (tree->type == LOG) {
  1603. arg1 = eval_tree(tree->left,i);
  1604. if (arg1 <= 0.0)
  1605. error->one("Log of zero/negative value in variable formula");
  1606. return log10(arg1);
  1607. }
  1608. if (tree->type == SIN)
  1609. return sin(eval_tree(tree->left,i));
  1610. if (tree->type == COS)
  1611. return cos(eval_tree(tree->left,i));
  1612. if (tree->type == TAN)
  1613. return tan(eval_tree(tree->left,i));
  1614. if (tree->type == ASIN) {
  1615. arg1 = eval_tree(tree->left,i);
  1616. if (arg1 < -1.0 || arg1 > 1.0)
  1617. error->one("Arcsin of invalid value in variable formula");
  1618. return asin(arg1);
  1619. }
  1620. if (tree->type == ACOS) {
  1621. arg1 = eval_tree(tree->left,i);
  1622. if (arg1 < -1.0 || arg1 > 1.0)
  1623. error->one("Arccos of invalid value in variable formula");
  1624. return acos(arg1);
  1625. }
  1626. if (tree->type == ATAN)
  1627. return atan(eval_tree(tree->left,i));
  1628. if (tree->type == ATAN2)
  1629. return atan2(eval_tree(tree->left,i),eval_tree(tree->right,i));
  1630. if (tree->type == RANDOM) {
  1631. double lower = eval_tree(tree->left,i);
  1632. double upper = eval_tree(tree->middle,i);
  1633. if (randomatom == NULL) {
  1634. int seed = static_cast<int> (eval_tree(tree->right,i));
  1635. if (seed <= 0) error->one("Invalid math function in variable formula");
  1636. randomatom = new RanMars(lmp,seed+me);
  1637. }
  1638. return randomatom->uniform()*(upper-lower)+lower;
  1639. }
  1640. if (tree->type == NORMAL) {
  1641. double mu = eval_tree(tree->left,i);
  1642. double sigma = eval_tree(tree->middle,i);
  1643. if (sigma < 0.0) error->one("Invalid math function in variable formula");
  1644. if (randomatom == NULL) {
  1645. int seed = static_cast<int> (eval_tree(tree->right,i));
  1646. if (seed <= 0) error->one("Invalid math function in variable formula");
  1647. randomatom = new RanMars(lmp,seed+me);
  1648. }
  1649. return mu + sigma*randomatom->gaussian();
  1650. }
  1651. if (tree->type == CEIL)
  1652. return ceil(eval_tree(tree->left,i));
  1653. if (tree->type == FLOOR)
  1654. return floor(eval_tree(tree->left,i));
  1655. if (tree->type == ROUND)
  1656. return MYROUND(eval_tree(tree->left,i));
  1657. if (tree->type == RAMP) {
  1658. arg1 = eval_tree(tree->left,i);
  1659. arg2 = eval_tree(tree->right,i);
  1660. double delta = update->ntimestep - update->beginstep;
  1661. delta /= update->endstep - update->beginstep;
  1662. arg = arg1 + delta*(arg2-arg1);
  1663. return arg;
  1664. }
  1665. if (tree->type == STAGGER) {
  1666. int ivalue1 = static_cast<int> (eval_tree(tree->left,i));
  1667. int ivalue2 = static_cast<int> (eval_tree(tree->right,i));
  1668. if (ivalue1 <= 0 || ivalue2 <= 0 || ivalue1 <= ivalue2)
  1669. error->one("Invalid math function in variable formula");
  1670. int lower = update->ntimestep/ivalue1 * ivalue1;
  1671. int delta = update->ntimestep - lower;
  1672. if (delta < ivalue2) arg = lower+ivalue2;
  1673. else arg = lower+ivalue1;
  1674. return arg;
  1675. }
  1676. if (tree->type == LOGFREQ) {
  1677. int ivalue1 = static_cast<int> (eval_tree(tree->left,i));
  1678. int ivalue2 = static_cast<int> (eval_tree(tree->middle,i));
  1679. int ivalue3 = static_cast<int> (eval_tree(tree->right,i));
  1680. if (ivalue1 <= 0 || ivalue2 <= 0 || ivalue3 <= 0 || ivalue2 >= ivalue3)
  1681. error->one("Invalid math function in variable formula");
  1682. if (update->ntimestep < ivalue1) arg = ivalue1;
  1683. else {
  1684. int lower = ivalue1;
  1685. while (update->ntimestep >= ivalue3*lower) lower *= ivalue3;
  1686. int multiple = update->ntimestep/lower;
  1687. if (multiple < ivalue2) arg = (multiple+1)*lower;
  1688. else arg = lower*ivalue3;
  1689. }
  1690. return arg;
  1691. }
  1692. if (tree->type == VDISPLACE) {
  1693. arg1 = eval_tree(tree->left,i);
  1694. arg2 = eval_tree(tree->right,i);
  1695. double delta = update->ntimestep - update->beginstep;
  1696. arg = arg1 + arg2*delta*update->dt;
  1697. return arg;
  1698. }
  1699. if (tree->type == SWIGGLE) {
  1700. arg1 = eval_tree(tree->left,i);
  1701. arg2 = eval_tree(tree->middle,i);
  1702. arg3 = eval_tree(tree->right,i);
  1703. if (arg3 == 0.0) error->one("Invalid math function in variable formula");
  1704. double delta = update->ntimestep - update->beginstep;
  1705. double omega = 2.0*PI/arg3;
  1706. arg = arg1 + arg2*sin(omega*delta*update->dt);
  1707. return arg;
  1708. }
  1709. if (tree->type == CWIGGLE) {
  1710. arg1 = eval_tree(tree->left,i);
  1711. arg2 = eval_tree(tree->middle,i);
  1712. arg3 = eval_tree(tree->right,i);
  1713. if (arg3 == 0.0) error->one("Invalid math function in variable formula");
  1714. double delta = update->ntimestep - update->beginstep;
  1715. double omega = 2.0*PI/arg3;
  1716. arg = arg1 + arg2*(1.0-cos(omega*delta*update->dt));
  1717. return arg;
  1718. }
  1719. if (tree->type == GMASK) {
  1720. if (atom->mask[i] & tree->ivalue1) return 1.0;
  1721. else return 0.0;
  1722. }
  1723. if (tree->type == RMASK) {
  1724. if (domain->regions[tree->ivalue1]->inside(atom->x[i][0],
  1725. atom->x[i][1],
  1726. atom->x[i][2])) return 1.0;
  1727. else return 0.0;
  1728. }
  1729. if (tree->type == GRMASK) {
  1730. if ((atom->mask[i] & tree->ivalue1) &&
  1731. (domain->regions[tree->ivalue2]->inside(atom->x[i][0],
  1732. atom->x[i][1],
  1733. atom->x[i][2]))) return 1.0;
  1734. else return 0.0;
  1735. }
  1736. return 0.0;
  1737. }
  1738. /* ---------------------------------------------------------------------- */
  1739. void Variable::free_tree(Tree *tree)
  1740. {
  1741. if (tree->left) free_tree(tree->left);
  1742. if (tree->middle) free_tree(tree->middle);
  1743. if (tree->right) free_tree(tree->right);
  1744. delete tree;
  1745. }
  1746. /* ----------------------------------------------------------------------
  1747. find matching parenthesis in str, allocate contents = str between parens
  1748. i = left paren
  1749. return loc or right paren
  1750. ------------------------------------------------------------------------- */
  1751. int Variable::find_matching_paren(char *str, int i,char *&contents)
  1752. {
  1753. // istop = matching ')' at same level, allowing for nested parens
  1754. int istart = i;
  1755. int ilevel = 0;
  1756. while (1) {
  1757. i++;
  1758. if (!str[i]) break;
  1759. if (str[i] == '(') ilevel++;
  1760. else if (str[i] == ')' && ilevel) ilevel--;
  1761. else if (str[i] == ')') break;
  1762. }
  1763. if (!str[i]) error->all("Invalid syntax in variable formula");
  1764. int istop = i;
  1765. int n = istop - istart - 1;
  1766. contents = new char[n+1];
  1767. strncpy(contents,&str[istart+1],n);
  1768. contents[n] = '\0';
  1769. return istop;
  1770. }
  1771. /* ----------------------------------------------------------------------
  1772. find int between brackets and return it
  1773. ptr initially points to left bracket
  1774. return it pointing to right bracket
  1775. error if no right bracket or brackets are empty
  1776. error if any between-bracket chars are non-digits or value == 0
  1777. ------------------------------------------------------------------------- */
  1778. int Variable::int_between_brackets(char *&ptr)
  1779. {
  1780. char *start = ++ptr;
  1781. while (*ptr && *ptr != ']') {
  1782. if (!isdigit(*ptr))
  1783. error->all("Non digit character between brackets in variable");
  1784. ptr++;
  1785. }
  1786. if (*ptr != ']') error->all("Mismatched brackets in variable");
  1787. if (ptr == start) error->all("Empty brackets in variable");
  1788. *ptr = '\0';
  1789. int index = atoi(start);
  1790. *ptr = ']';
  1791. if (index == 0)
  1792. error->all("Index between variable brackets must be positive");
  1793. return index;
  1794. }
  1795. /* ----------------------------------------------------------------------
  1796. process a math function in formula
  1797. push result onto tree or arg stack
  1798. word = math function
  1799. contents = str between parentheses with one,two,three args
  1800. return 0 if not a match, 1 if successfully processed
  1801. customize by adding a math function:
  1802. sqrt(),exp(),ln(),log(),sin(),cos(),tan(),asin(),acos(),atan(),
  1803. atan2(y,x),random(x,y,z),normal(x,y,z),ceil(),floor(),round(),
  1804. ramp(x,y),stagger(x,y),logfreq(x,y,z),
  1805. vdisplace(x,y),swiggle(x,y,z),cwiggle(x,y,z)
  1806. ------------------------------------------------------------------------- */
  1807. int Variable::math_function(char *word, char *contents, Tree **tree,
  1808. Tree **treestack, int &ntreestack,
  1809. double *argstack, int &nargstack)
  1810. {
  1811. // word not a match to any math function
  1812. if (strcmp(word,"sqrt") && strcmp(word,"exp") &&
  1813. strcmp(word,"ln") && strcmp(word,"log") &&
  1814. strcmp(word,"sin") && strcmp(word,"cos") &&
  1815. strcmp(word,"tan") && strcmp(word,"asin") &&
  1816. strcmp(word,"acos") && strcmp(word,"atan") &&
  1817. strcmp(word,"atan2") && strcmp(word,"random") &&
  1818. strcmp(word,"normal") && strcmp(word,"ceil") &&
  1819. strcmp(word,"floor") && strcmp(word,"round") &&
  1820. strcmp(word,"ramp") && strcmp(word,"stagger") &&
  1821. strcmp(word,"logfreq") && strcmp(word,"vdisplace") &&
  1822. strcmp(word,"swiggle") && strcmp(word,"cwiggle"))
  1823. return 0;
  1824. // parse contents for arg1,arg2,arg3 separated by commas
  1825. // ptr1,ptr2 = location of 1st and 2nd comma, NULL if none
  1826. char *arg1,*arg2,*arg3;
  1827. char *ptr1,*ptr2;
  1828. ptr1 = strchr(contents,',');
  1829. if (ptr1) {
  1830. *ptr1 = '\0';
  1831. ptr2 = strchr(ptr1+1,',');
  1832. if (ptr2) *ptr2 = '\0';
  1833. } else ptr2 = NULL;
  1834. int n = strlen(contents) + 1;
  1835. arg1 = new char[n];
  1836. strcpy(arg1,contents);
  1837. int narg = 1;
  1838. if (ptr1) {
  1839. n = strlen(ptr1+1) + 1;
  1840. arg2 = new char[n];
  1841. strcpy(arg2,ptr1+1);
  1842. narg = 2;
  1843. } else arg2 = NULL;
  1844. if (ptr2) {
  1845. n = strlen(ptr2+1) + 1;
  1846. arg3 = new char[n];
  1847. strcpy(arg3,ptr2+1);
  1848. narg = 3;
  1849. } else arg3 = NULL;
  1850. // evaluate args
  1851. Tree *newtree;
  1852. double tmp,value1,value2,value3;
  1853. if (tree) {
  1854. newtree = new Tree();
  1855. Tree *argtree;
  1856. if (narg == 1) {
  1857. tmp = evaluate(arg1,&argtree);
  1858. newtree->left = argtree;
  1859. newtree->middle = newtree->right = NULL;
  1860. } else if (narg == 2) {
  1861. tmp = evaluate(arg1,&argtree);
  1862. newtree->left = argtree;
  1863. newtree->middle = NULL;
  1864. tmp = evaluate(arg2,&argtree);
  1865. newtree->right = argtree;
  1866. } else if (narg == 3) {
  1867. tmp = evaluate(arg1,&argtree);
  1868. newtree->left = argtree;
  1869. tmp = evaluate(arg2,&argtree);
  1870. newtree->middle = argtree;
  1871. tmp = evaluate(arg3,&argtree);
  1872. newtree->right = argtree;
  1873. }
  1874. treestack[ntreestack++] = newtree;
  1875. } else {
  1876. if (narg == 1) {
  1877. value1 = evaluate(arg1,NULL);
  1878. } else if (narg == 2) {
  1879. value1 = evaluate(arg1,NULL);
  1880. value2 = evaluate(arg2,NULL);
  1881. } else if (narg == 3) {
  1882. value1 = evaluate(arg1,NULL);
  1883. value2 = evaluate(arg2,NULL);
  1884. value3 = evaluate(arg3,NULL);
  1885. }
  1886. }
  1887. if (strcmp(word,"sqrt") == 0) {
  1888. if (narg != 1) error->all("Invalid math function in variable formula");
  1889. if (tree) newtree->type = SQRT;
  1890. else {
  1891. if (value1 < 0.0)
  1892. error->all("Sqrt of negative value in variable formula");
  1893. argstack[nargstack++] = sqrt(value1);
  1894. }
  1895. } else if (strcmp(word,"exp") == 0) {
  1896. if (narg != 1) error->all("Invalid math function in variable formula");
  1897. if (tree) newtree->type = EXP;
  1898. else argstack[nargstack++] = exp(value1);
  1899. } else if (strcmp(word,"ln") == 0) {
  1900. if (narg != 1) error->all("Invalid math function in variable formula");
  1901. if (tree) newtree->type = LN;
  1902. else {
  1903. if (value1 <= 0.0)
  1904. error->all("Log of zero/negative value in variable formula");
  1905. argstack[nargstack++] = log(value1);
  1906. }
  1907. } else if (strcmp(word,"log") == 0) {
  1908. if (narg != 1) error->all("Invalid math function in variable formula");
  1909. if (tree) newtree->type = LOG;
  1910. else {
  1911. if (value1 <= 0.0)
  1912. error->all("Log of zero/negative value in variable formula");
  1913. argstack[nargstack++] = log10(value1);
  1914. }
  1915. } else if (strcmp(word,"sin") == 0) {
  1916. if (narg != 1) error->all("Invalid math function in variable formula");
  1917. if (tree) newtree->type = SIN;
  1918. else argstack[nargstack++] = sin(value1);
  1919. } else if (strcmp(word,"cos") == 0) {
  1920. if (narg != 1) error->all("Invalid math function in variable formula");
  1921. if (tree) newtree->type = COS;
  1922. else argstack[nargstack++] = cos(value1);
  1923. } else if (strcmp(word,"tan") == 0) {
  1924. if (narg != 1) error->all("Invalid math function in variable formula");
  1925. if (tree) newtree->type = TAN;
  1926. else argstack[nargstack++] = tan(value1);
  1927. } else if (strcmp(word,"asin") == 0) {
  1928. if (narg != 1) error->all("Invalid math function in variable formula");
  1929. if (tree) newtree->type = ASIN;
  1930. else {
  1931. if (value1 < -1.0 || value1 > 1.0)
  1932. error->all("Arcsin of invalid value in variable formula");
  1933. argstack[nargstack++] = asin(value1);
  1934. }
  1935. } else if (strcmp(word,"acos") == 0) {
  1936. if (narg != 1) error->all("Invalid math function in variable formula");
  1937. if (tree) newtree->type = ACOS;
  1938. else {
  1939. if (value1 < -1.0 || value1 > 1.0)
  1940. error->all("Arccos of invalid value in variable formula");
  1941. argstack[nargstack++] = acos(value1);
  1942. }
  1943. } else if (strcmp(word,"atan") == 0) {
  1944. if (narg != 1) error->all("Invalid math function in variable formula");
  1945. if (tree) newtree->type = ATAN;
  1946. else argstack[nargstack++] = atan(value1);
  1947. } else if (strcmp(word,"atan2") == 0) {
  1948. if (narg != 2) error->all("Invalid math function in variable formula");
  1949. if (tree) newtree->type = ATAN2;
  1950. else argstack[nargstack++] = atan2(value1,value2);
  1951. } else if (strcmp(word,"random") == 0) {
  1952. if (narg != 3) error->all("Invalid math function in variable formula");
  1953. if (tree) newtree->type = RANDOM;
  1954. else {
  1955. if (randomequal == NULL) {
  1956. int seed = static_cast<int> (value3);
  1957. if (seed <= 0) error->all("Invalid math function in variable formula");
  1958. randomequal = new RanMars(lmp,seed);
  1959. }
  1960. argstack[nargstack++] = randomequal->uniform()*(value2-value1) + value1;
  1961. }
  1962. } else if (strcmp(word,"normal") == 0) {
  1963. if (narg != 3) error->all("Invalid math function in variable formula");
  1964. if (tree) newtree->type = NORMAL;
  1965. else {
  1966. if (value2 < 0.0)
  1967. error->all("Invalid math function in variable formula");
  1968. if (randomequal == NULL) {
  1969. int seed = static_cast<int> (value3);
  1970. if (seed <= 0) error->all("Invalid math function in variable formula");
  1971. randomequal = new RanMars(lmp,seed);
  1972. }
  1973. argstack[nargstack++] = value1 + value2*randomequal->gaussian();
  1974. }
  1975. } else if (strcmp(word,"ceil") == 0) {
  1976. if (narg != 1) error->all("Invalid math function in variable formula");
  1977. if (tree) newtree->type = CEIL;
  1978. else argstack[nargstack++] = ceil(value1);
  1979. } else if (strcmp(word,"floor") == 0) {
  1980. if (narg != 1) error->all("Invalid math function in variable formula");
  1981. if (tree) newtree->type = FLOOR;
  1982. else argstack[nargstack++] = floor(value1);
  1983. } else if (strcmp(word,"round") == 0) {
  1984. if (narg != 1) error->all("Invalid math function in variable formula");
  1985. if (tree) newtree->type = ROUND;
  1986. else argstack[nargstack++] = MYROUND(value1);
  1987. } else if (strcmp(word,"ramp") == 0) {
  1988. if (narg != 2) error->all("Invalid math function in variable formula");
  1989. if (update->whichflag == 0)
  1990. error->all("Cannot use ramp in variable formula between runs");
  1991. if (tree) newtree->type = RAMP;
  1992. else {
  1993. double delta = update->ntimestep - update->beginstep;
  1994. delta /= update->endstep - update->beginstep;
  1995. double value = value1 + delta*(value2-value1);
  1996. argstack[nargstack++] = value;
  1997. }
  1998. } else if (strcmp(word,"stagger") == 0) {
  1999. if (narg != 2) error->all("Invalid math function in variable formula");
  2000. if (tree) newtree->type = STAGGER;
  2001. else {
  2002. int ivalue1 = static_cast<int> (value1);
  2003. int ivalue2 = static_cast<int> (value2);
  2004. if (ivalue1 <= 0 || ivalue2 <= 0 || ivalue1 <= ivalue2)
  2005. error->all("Invalid math function in variable formula");
  2006. int lower = update->ntimestep/ivalue1 * ivalue1;
  2007. int delta = update->ntimestep - lower;
  2008. double value;
  2009. if (delta < ivalue2) value = lower+ivalue2;
  2010. else value = lower+ivalue1;
  2011. argstack[nargstack++] = value;
  2012. }
  2013. } else if (strcmp(word,"logfreq") == 0) {
  2014. if (narg != 3) error->all("Invalid math function in variable formula");
  2015. if (tree) newtree->type = LOGFREQ;
  2016. else {
  2017. int ivalue1 = static_cast<int> (value1);
  2018. int ivalue2 = static_cast<int> (value2);
  2019. int ivalue3 = static_cast<int> (value3);
  2020. if (ivalue1 <= 0 || ivalue2 <= 0 || ivalue3 <= 0 || ivalue2 >= ivalue3)
  2021. error->all("Invalid math function in variable formula");
  2022. double value;
  2023. if (update->ntimestep < ivalue1) value = ivalue1;
  2024. else {
  2025. int lower = ivalue1;
  2026. while (update->ntimestep >= ivalue3*lower) lower *= ivalue3;
  2027. int multiple = update->ntimestep/lower;
  2028. if (multiple < ivalue2) value = (multiple+1)*lower;
  2029. else value = lower*ivalue3;
  2030. }
  2031. argstack[nargstack++] = value;
  2032. }
  2033. } else if (strcmp(word,"vdisplace") == 0) {
  2034. if (narg != 2) error->all("Invalid math function in variable formula");
  2035. if (update->whichflag == 0)
  2036. error->all("Cannot use vdisplace in variable formula between runs");
  2037. if (tree) newtree->type = VDISPLACE;
  2038. else {
  2039. double delta = update->ntimestep - update->beginstep;
  2040. double value = value1 + value2*delta*update->dt;
  2041. argstack[nargstack++] = value;
  2042. }
  2043. } else if (strcmp(word,"swiggle") == 0) {
  2044. if (narg != 3) error->all("Invalid math function in variable formula");
  2045. if (update->whichflag == 0)
  2046. error->all("Cannot use swiggle in variable formula between runs");
  2047. if (tree) newtree->type = CWIGGLE;
  2048. else {
  2049. if (value3 == 0.0)
  2050. error->all("Invalid math function in variable formula");
  2051. double delta = update->ntimestep - update->beginstep;
  2052. double omega = 2.0*PI/value3;
  2053. double value = value1 + value2*sin(omega*delta*update->dt);
  2054. argstack[nargstack++] = value;
  2055. }
  2056. } else if (strcmp(word,"cwiggle") == 0) {
  2057. if (narg != 3) error->all("Invalid math function in variable formula");
  2058. if (update->whichflag == 0)
  2059. error->all("Cannot use cwiggle in variable formula between runs");
  2060. if (tree) newtree->type = CWIGGLE;
  2061. else {
  2062. if (value3 == 0.0)
  2063. error->all("Invalid math function in variable formula");
  2064. double delta = update->ntimestep - update->beginstep;
  2065. double omega = 2.0*PI/value3;
  2066. double value = value1 + value2*(1.0-cos(omega*delta*update->dt));
  2067. argstack[nargstack++] = value;
  2068. }
  2069. }
  2070. delete [] arg1;
  2071. delete [] arg2;
  2072. delete [] arg3;
  2073. return 1;
  2074. }
  2075. /* ----------------------------------------------------------------------
  2076. process a group function in formula with optional region arg
  2077. push result onto tree or arg stack
  2078. word = group function
  2079. contents = str between parentheses with one,two,three args
  2080. return 0 if not a match, 1 if successfully processed
  2081. customize by adding a group function with optional region arg:
  2082. count(group),mass(group),charge(group),
  2083. xcm(group,dim),vcm(group,dim),fcm(group,dim),
  2084. bound(group,xmin),gyration(group),ke(group),angmom(group,dim),
  2085. torque(group,dim),inertia(group,dim),omega(group,dim)
  2086. ------------------------------------------------------------------------- */
  2087. int Variable::group_function(char *word, char *contents, Tree **tree,
  2088. Tree **treestack, int &ntreestack,
  2089. double *argstack, int &nargstack)
  2090. {
  2091. // word not a match to any group function
  2092. if (strcmp(word,"count") && strcmp(word,"mass") &&
  2093. strcmp(word,"charge") && strcmp(word,"xcm") &&
  2094. strcmp(word,"vcm") && strcmp(word,"fcm") &&
  2095. strcmp(word,"bound") && strcmp(word,"gyration") &&
  2096. strcmp(word,"ke") && strcmp(word,"angmom") &&
  2097. strcmp(word,"torque") && strcmp(word,"inertia") &&
  2098. strcmp(word,"omega"))
  2099. return 0;
  2100. // parse contents for arg1,arg2,arg3 separated by commas
  2101. // ptr1,ptr2 = location of 1st and 2nd comma, NULL if none
  2102. char *arg1,*arg2,*arg3;
  2103. char *ptr1,*ptr2;
  2104. ptr1 = strchr(contents,',');
  2105. if (ptr1) {
  2106. *ptr1 = '\0';
  2107. ptr2 = strchr(ptr1+1,',');
  2108. if (ptr2) *ptr2 = '\0';
  2109. } else ptr2 = NULL;
  2110. int n = strlen(contents) + 1;
  2111. arg1 = new char[n];
  2112. strcpy(arg1,contents);
  2113. int narg = 1;
  2114. if (ptr1) {
  2115. n = strlen(ptr1+1) + 1;
  2116. arg2 = new char[n];
  2117. strcpy(arg2,ptr1+1);
  2118. narg = 2;
  2119. } else arg2 = NULL;
  2120. if (ptr2) {
  2121. n = strlen(ptr2+1) + 1;
  2122. arg3 = new char[n];
  2123. strcpy(arg3,ptr2+1);
  2124. narg = 3;
  2125. } else arg3 = NULL;
  2126. // group to operate on
  2127. int igroup = group->find(arg1);
  2128. if (igroup == -1)
  2129. error->all("Group ID in variable formula does not exist");
  2130. // match word to group function
  2131. double value;
  2132. if (strcmp(word,"count") == 0) {
  2133. if (narg == 1) value = group->count(igroup);
  2134. else if (narg == 2) value = group->count(igroup,region_function(arg2));
  2135. else error->all("Invalid group function in variable formula");
  2136. } else if (strcmp(word,"mass") == 0) {
  2137. if (narg == 1) value = group->mass(igroup);
  2138. else if (narg == 2) value = group->mass(igroup,region_function(arg2));
  2139. else error->all("Invalid group function in variable formula");
  2140. } else if (strcmp(word,"charge") == 0) {
  2141. if (narg == 1) value = group->charge(igroup);
  2142. else if (narg == 2) value = group->charge(igroup,region_function(arg2));
  2143. else error->all("Invalid group function in variable formula");
  2144. } else if (strcmp(word,"xcm") == 0) {
  2145. atom->check_mass();
  2146. double xcm[3];
  2147. if (narg == 2) {
  2148. double masstotal = group->mass(igroup);
  2149. group->xcm(igroup,masstotal,xcm);
  2150. } else if (narg == 3) {
  2151. int iregion = region_function(arg3);
  2152. double masstotal = group->mass(igroup,iregion);
  2153. group->xcm(igroup,masstotal,xcm,iregion);
  2154. } else error->all("Invalid group function in variable formula");
  2155. if (strcmp(arg2,"x") == 0) value = xcm[0];
  2156. else if (strcmp(arg2,"y") == 0) value = xcm[1];
  2157. else if (strcmp(arg2,"z") == 0) value = xcm[2];
  2158. else error->all("Invalid group function in variable formula");
  2159. } else if (strcmp(word,"vcm") == 0) {
  2160. atom->check_mass();
  2161. double vcm[3];
  2162. if (narg == 2) {
  2163. double masstotal = group->mass(igroup);
  2164. group->vcm(igroup,masstotal,vcm);
  2165. } else if (narg == 3) {
  2166. int iregion = region_function(arg3);
  2167. double masstotal = group->mass(igroup,iregion);
  2168. group->vcm(igroup,masstotal,vcm,iregion);
  2169. } else error->all("Invalid group function in variable formula");
  2170. if (strcmp(arg2,"x") == 0) value = vcm[0];
  2171. else if (strcmp(arg2,"y") == 0) value = vcm[1];
  2172. else if (strcmp(arg2,"z") == 0) value = vcm[2];
  2173. else error->all("Invalid group function in variable formula");
  2174. } else if (strcmp(word,"fcm") == 0) {
  2175. double fcm[3];
  2176. if (narg == 2) group->fcm(igroup,fcm);
  2177. else if (narg == 3) group->fcm(igroup,fcm,region_function(arg3));
  2178. else error->all("Invalid group function in variable formula");
  2179. if (strcmp(arg2,"x") == 0) value = fcm[0];
  2180. else if (strcmp(arg2,"y") == 0) value = fcm[1];
  2181. else if (strcmp(arg2,"z") == 0) value = fcm[2];
  2182. else error->all("Invalid group function in variable formula");
  2183. } else if (strcmp(word,"bound") == 0) {
  2184. double minmax[6];
  2185. if (narg == 2) group->bounds(igroup,minmax);
  2186. else if (narg == 3) group->bounds(igroup,minmax,region_function(arg3));
  2187. else error->all("Invalid group function in variable formula");
  2188. if (strcmp(arg2,"xmin") == 0) value = minmax[0];
  2189. else if (strcmp(arg2,"xmax") == 0) value = minmax[1];
  2190. else if (strcmp(arg2,"ymin") == 0) value = minmax[2];
  2191. else if (strcmp(arg2,"ymax") == 0) value = minmax[3];
  2192. else if (strcmp(arg2,"zmin") == 0) value = minmax[4];
  2193. else if (strcmp(arg2,"zmax") == 0) value = minmax[5];
  2194. else error->all("Invalid group function in variable formula");
  2195. } else if (strcmp(word,"gyration") == 0) {
  2196. atom->check_mass();
  2197. double xcm[3];
  2198. if (narg == 1) {
  2199. double masstotal = group->mass(igroup);
  2200. group->xcm(igroup,masstotal,xcm);
  2201. value = group->gyration(igroup,masstotal,xcm);
  2202. } else if (narg == 2) {
  2203. int iregion = region_function(arg2);
  2204. double masstotal = group->mass(igroup,iregion);
  2205. group->xcm(igroup,masstotal,xcm,iregion);
  2206. value = group->gyration(igroup,masstotal,xcm,iregion);
  2207. } else error->all("Invalid group function in variable formula");
  2208. } else if (strcmp(word,"ke") == 0) {
  2209. if (narg == 1) value = group->ke(igroup);
  2210. else if (narg == 2) value = group->ke(igroup,region_function(arg2));
  2211. else error->all("Invalid group function in variable formula");
  2212. } else if (strcmp(word,"angmom") == 0) {
  2213. atom->check_mass();
  2214. double xcm[3],lmom[3];
  2215. if (narg == 2) {
  2216. double masstotal = group->mass(igroup);
  2217. group->xcm(igroup,masstotal,xcm);
  2218. group->angmom(igroup,xcm,lmom);
  2219. } else if (narg == 3) {
  2220. int iregion = region_function(arg3);
  2221. double masstotal = group->mass(igroup,iregion);
  2222. group->xcm(igroup,masstotal,xcm,iregion);
  2223. group->angmom(igroup,xcm,lmom,iregion);
  2224. } else error->all("Invalid group function in variable formula");
  2225. if (strcmp(arg2,"x") == 0) value = lmom[0];
  2226. else if (strcmp(arg2,"y") == 0) value = lmom[1];
  2227. else if (strcmp(arg2,"z") == 0) value = lmom[2];
  2228. else error->all("Invalid group function in variable formula");
  2229. } else if (strcmp(word,"torque") == 0) {
  2230. atom->check_mass();
  2231. double xcm[3],tq[3];
  2232. if (narg == 2) {
  2233. double masstotal = group->mass(igroup);
  2234. group->xcm(igroup,masstotal,xcm);
  2235. group->torque(igroup,xcm,tq);
  2236. } else if (narg == 3) {
  2237. int iregion = region_function(arg3);
  2238. double masstotal = group->mass(igroup,iregion);
  2239. group->xcm(igroup,masstotal,xcm,iregion);
  2240. group->torque(igroup,xcm,tq,iregion);
  2241. } else error->all("Invalid group function in variable formula");
  2242. if (strcmp(arg2,"x") == 0) value = tq[0];
  2243. else if (strcmp(arg2,"y") == 0) value = tq[1];
  2244. else if (strcmp(arg2,"z") == 0) value = tq[2];
  2245. else error->all("Invalid group function in variable formula");
  2246. } else if (strcmp(word,"inertia") == 0) {
  2247. atom->check_mass();
  2248. double xcm[3],inertia[3][3];
  2249. if (narg == 2) {
  2250. double masstotal = group->mass(igroup);
  2251. group->xcm(igroup,masstotal,xcm);
  2252. group->inertia(igroup,xcm,inertia);
  2253. } else if (narg == 3) {
  2254. int iregion = region_function(arg3);
  2255. double masstotal = group->mass(igroup,iregion);
  2256. group->xcm(igroup,masstotal,xcm,iregion);
  2257. group->inertia(igroup,xcm,inertia,iregion);
  2258. } else error->all("Invalid group function in variable formula");
  2259. if (strcmp(arg2,"xx") == 0) value = inertia[0][0];
  2260. else if (strcmp(arg2,"yy") == 0) value = inertia[1][1];
  2261. else if (strcmp(arg2,"zz") == 0) value = inertia[2][2];
  2262. else if (strcmp(arg2,"xy") == 0) value = inertia[0][1];
  2263. else if (strcmp(arg2,"yz") == 0) value = inertia[1][2];
  2264. else if (strcmp(arg2,"xz") == 0) value = inertia[0][2];
  2265. else error->all("Invalid group function in variable formula");
  2266. } else if (strcmp(word,"omega") == 0) {
  2267. atom->check_mass();
  2268. double xcm[3],angmom[3],inertia[3][3],omega[3];
  2269. if (narg == 2) {
  2270. double masstotal = group->mass(igroup);
  2271. group->xcm(igroup,masstotal,xcm);
  2272. group->angmom(igroup,xcm,angmom);
  2273. group->inertia(igroup,xcm,inertia);
  2274. group->omega(angmom,inertia,omega);
  2275. } else if (narg == 3) {
  2276. int iregion = region_function(arg3);
  2277. double masstotal = group->mass(igroup,iregion);
  2278. group->xcm(igroup,masstotal,xcm,iregion);
  2279. group->angmom(igroup,xcm,angmom,iregion);
  2280. group->inertia(igroup,xcm,inertia,iregion);
  2281. group->omega(angmom,inertia,omega);
  2282. } else error->all("Invalid group function in variable formula");
  2283. if (strcmp(arg2,"x") == 0) value = omega[0];
  2284. else if (strcmp(arg2,"y") == 0) value = omega[1];
  2285. else if (strcmp(arg2,"z") == 0) value = omega[2];
  2286. else error->all("Invalid group function in variable formula");
  2287. }
  2288. delete [] arg1;
  2289. delete [] arg2;
  2290. delete [] arg3;
  2291. // save value in tree or on argstack
  2292. if (tree) {
  2293. Tree *newtree = new Tree();
  2294. newtree->type = VALUE;
  2295. newtree->value = value;
  2296. newtree->left = newtree->middle = newtree->right = NULL;
  2297. treestack[ntreestack++] = newtree;
  2298. } else argstack[nargstack++] = value;
  2299. return 1;
  2300. }
  2301. /* ---------------------------------------------------------------------- */
  2302. int Variable::region_function(char *id)
  2303. {
  2304. int iregion = domain->find_region(id);
  2305. if (iregion == -1)
  2306. error->all("Region ID in variable formula does not exist");
  2307. return iregion;
  2308. }
  2309. /* ----------------------------------------------------------------------
  2310. process a special function in formula
  2311. push result onto tree or arg stack
  2312. word = special function
  2313. contents = str between parentheses with one,two,three args
  2314. return 0 if not a match, 1 if successfully processed
  2315. customize by adding a special function:
  2316. sum(x),min(x),max(x),ave(x),trap(x),gmask(x),rmask(x),grmask(x,y)
  2317. ------------------------------------------------------------------------- */
  2318. int Variable::special_function(char *word, char *contents, Tree **tree,
  2319. Tree **treestack, int &ntreestack,
  2320. double *argstack, int &nargstack)
  2321. {
  2322. // word not a match to any special function
  2323. if (strcmp(word,"sum") && strcmp(word,"min") && strcmp(word,"max") &&
  2324. strcmp(word,"ave") && strcmp(word,"trap") && strcmp(word,"gmask") &&
  2325. strcmp(word,"rmask") && strcmp(word,"grmask"))
  2326. return 0;
  2327. // parse contents for arg1,arg2,arg3 separated by commas
  2328. // ptr1,ptr2 = location of 1st and 2nd comma, NULL if none
  2329. char *arg1,*arg2,*arg3;
  2330. char *ptr1,*ptr2;
  2331. ptr1 = strchr(contents,',');
  2332. if (ptr1) {
  2333. *ptr1 = '\0';
  2334. ptr2 = strchr(ptr1+1,',');
  2335. if (ptr2) *ptr2 = '\0';
  2336. } else ptr2 = NULL;
  2337. int n = strlen(contents) + 1;
  2338. arg1 = new char[n];
  2339. strcpy(arg1,contents);
  2340. int narg = 1;
  2341. if (ptr1) {
  2342. n = strlen(ptr1+1) + 1;
  2343. arg2 = new char[n];
  2344. strcpy(arg2,ptr1+1);
  2345. narg = 2;
  2346. } else arg2 = NULL;
  2347. if (ptr2) {
  2348. n = strlen(ptr2+1) + 1;
  2349. arg3 = new char[n];
  2350. strcpy(arg3,ptr2+1);
  2351. narg = 3;
  2352. } else arg3 = NULL;
  2353. // special functions that operate on global vectors
  2354. if (strcmp(word,"sum") == 0 || strcmp(word,"min") == 0 ||
  2355. strcmp(word,"max") == 0 || strcmp(word,"ave") == 0 ||
  2356. strcmp(word,"trap") == 0) {
  2357. int method;
  2358. if (strcmp(word,"sum") == 0) method = SUM;
  2359. else if (strcmp(word,"min") == 0) method = XMIN;
  2360. else if (strcmp(word,"max") == 0) method = XMAX;
  2361. else if (strcmp(word,"ave") == 0) method = AVE;
  2362. else if (strcmp(word,"trap") == 0) method = TRAP;
  2363. if (narg != 1) error->all("Invalid special function in variable formula");
  2364. Compute *compute = NULL;
  2365. Fix *fix = NULL;
  2366. int index,nvec,nstride;
  2367. if (strstr(arg1,"c_") == arg1) {
  2368. ptr1 = strchr(arg1,'[');
  2369. if (ptr1) {
  2370. ptr2 = ptr1;
  2371. index = int_between_brackets(ptr2);
  2372. *ptr1 = '\0';
  2373. } else index = 0;
  2374. int icompute = modify->find_compute(&arg1[2]);
  2375. if (icompute < 0) error->all("Invalid compute ID in variable formula");
  2376. compute = modify->compute[icompute];
  2377. if (index == 0 && compute->vector_flag) {
  2378. if (update->whichflag == 0) {
  2379. if (compute->invoked_vector != update->ntimestep)
  2380. error->all("Compute used in variable between runs is not current");
  2381. } else if (!(compute->invoked_flag & INVOKED_VECTOR)) {
  2382. compute->compute_vector();
  2383. compute->invoked_flag |= INVOKED_VECTOR;
  2384. }
  2385. nvec = compute->size_vector;
  2386. nstride = 1;
  2387. } else if (index && compute->array_flag) {
  2388. if (index > compute->size_array_cols)
  2389. error->all("Variable formula compute array "
  2390. "is accessed out-of-range");
  2391. if (update->whichflag == 0) {
  2392. if (compute->invoked_array != update->ntimestep)
  2393. error->all("Compute used in variable between runs is not current");
  2394. } else if (!(compute->invoked_flag & INVOKED_ARRAY)) {
  2395. compute->compute_array();
  2396. compute->invoked_flag |= INVOKED_ARRAY;
  2397. }
  2398. nvec = compute->size_array_rows;
  2399. nstride = compute->size_array_cols;
  2400. } else error->all("Mismatched compute in variable formula");
  2401. } else if (strstr(arg1,"f_") == arg1) {
  2402. ptr1 = strchr(arg1,'[');
  2403. if (ptr1) {
  2404. ptr2 = ptr1;
  2405. index = int_between_brackets(ptr2);
  2406. *ptr1 = '\0';
  2407. } else index = 0;
  2408. int ifix = modify->find_fix(&arg1[2]);
  2409. if (ifix < 0) error->all("Invalid fix ID in variable formula");
  2410. fix = modify->fix[ifix];
  2411. if (index == 0 && fix->vector_flag) {
  2412. if (update->whichflag > 0 && update->ntimestep % fix->global_freq)
  2413. error->all("Fix in variable not computed at compatible time");
  2414. nvec = fix->size_vector;
  2415. nstride = 1;
  2416. } else if (index && fix->array_flag) {
  2417. if (index > fix->size_array_cols)
  2418. error->all("Variable formula fix array is accessed out-of-range");
  2419. if (update->whichflag > 0 && update->ntimestep % fix->global_freq)
  2420. error->all("Fix in variable not computed at compatible time");
  2421. nvec = fix->size_array_rows;
  2422. nstride = fix->size_array_cols;
  2423. } else error->all("Mismatched fix in variable formula");
  2424. } else error->all("Invalid special function in variable formula");
  2425. double value = 0.0;
  2426. if (method == XMIN) value = BIG;
  2427. if (method == XMAX) value = -BIG;
  2428. if (compute) {
  2429. double *vec;
  2430. if (index) vec = &compute->array[0][index-1];
  2431. else vec = compute->vector;
  2432. int j = 0;
  2433. for (int i = 0; i < nvec; i++) {
  2434. if (method == SUM) value += vec[j];
  2435. else if (method == XMIN) value = MIN(value,vec[j]);
  2436. else if (method == XMAX) value = MAX(value,vec[j]);
  2437. else if (method == AVE) value += vec[j];
  2438. else if (method == TRAP) {
  2439. if (i > 0 && i < nvec-1) value += vec[j];
  2440. else value += 0.5*vec[j];
  2441. }
  2442. j += nstride;
  2443. }
  2444. }
  2445. if (fix) {
  2446. double one;
  2447. for (int i = 0; i < nvec; i++) {
  2448. if (index) one = fix->compute_array(i,index-1);
  2449. else one = fix->compute_vector(i);
  2450. if (method == SUM) value += one;
  2451. else if (method == XMIN) value = MIN(value,one);
  2452. else if (method == XMAX) value = MAX(value,one);
  2453. else if (method == AVE) value += one;
  2454. else if (method == TRAP) {
  2455. if (i > 1 && i < nvec) value += one;
  2456. else value += 0.5*one;
  2457. }
  2458. }
  2459. }
  2460. if (method == AVE) value /= nvec;
  2461. delete [] arg1;
  2462. delete [] arg2;
  2463. delete [] arg3;
  2464. // save value in tree or on argstack
  2465. if (tree) {
  2466. Tree *newtree = new Tree();
  2467. newtree->type = VALUE;
  2468. newtree->value = value;
  2469. newtree->left = newtree->middle = newtree->right = NULL;
  2470. treestack[ntreestack++] = newtree;
  2471. } else argstack[nargstack++] = value;
  2472. // mask special functions
  2473. } else if (strcmp(word,"gmask") == 0) {
  2474. if (tree == NULL)
  2475. error->all("Gmask function in equal-style variable formula");
  2476. if (narg != 1) error->all("Invalid special function in variable formula");
  2477. int igroup = group->find(arg1);
  2478. if (igroup == -1)
  2479. error->all("Group ID in variable formula does not exist");
  2480. Tree *newtree = new Tree();
  2481. newtree->type = GMASK;
  2482. newtree->ivalue1 = group->bitmask[igroup];
  2483. newtree->left = newtree->middle = newtree->right = NULL;
  2484. treestack[ntreestack++] = newtree;
  2485. } else if (strcmp(word,"rmask") == 0) {
  2486. if (tree == NULL)
  2487. error->all("Rmask function in equal-style variable formula");
  2488. if (narg != 1) error->all("Invalid special function in variable formula");
  2489. int iregion = region_function(arg1);
  2490. Tree *newtree = new Tree();
  2491. newtree->type = RMASK;
  2492. newtree->ivalue1 = iregion;
  2493. newtree->left = newtree->middle = newtree->right = NULL;
  2494. treestack[ntreestack++] = newtree;
  2495. } else if (strcmp(word,"grmask") == 0) {
  2496. if (tree == NULL)
  2497. error->all("Grmask function in equal-style variable formula");
  2498. if (narg != 2) error->all("Invalid special function in variable formula");
  2499. int igroup = group->find(arg1);
  2500. if (igroup == -1)
  2501. error->all("Group ID in variable formula does not exist");
  2502. int iregion = region_function(arg2);
  2503. Tree *newtree = new Tree();
  2504. newtree->type = RMASK;
  2505. newtree->ivalue1 = group->bitmask[igroup];
  2506. newtree->ivalue2 = iregion;
  2507. newtree->left = newtree->middle = newtree->right = NULL;
  2508. treestack[ntreestack++] = newtree;
  2509. }
  2510. return 1;
  2511. }
  2512. /* ----------------------------------------------------------------------
  2513. extract a global value from a per-atom quantity in a formula
  2514. flag = 0 -> word is an atom vector
  2515. flag = 1 -> vector is a per-atom compute or fix quantity with nstride
  2516. id = positive global ID of atom, converted to local index
  2517. push result onto tree or arg stack
  2518. customize by adding an atom vector:
  2519. mass,type,x,y,z,vx,vy,vz,fx,fy,fz
  2520. ------------------------------------------------------------------------- */
  2521. void Variable::peratom2global(int flag, char *word,
  2522. double *vector, int nstride, int id,
  2523. Tree **tree, Tree **treestack, int &ntreestack,
  2524. double *argstack, int &nargstack)
  2525. {
  2526. if (atom->map_style == 0)
  2527. error->all("Indexed per-atom vector in variable formula without atom map");
  2528. int index = atom->map(id);
  2529. double mine;
  2530. if (index >= 0 && index < atom->nlocal) {
  2531. if (flag == 0) {
  2532. if (strcmp(word,"mass") == 0) {
  2533. if (atom->rmass) mine = atom->rmass[index];
  2534. else mine = atom->mass[atom->type[index]];
  2535. }
  2536. else if (strcmp(word,"type") == 0) mine = atom->type[index];
  2537. else if (strcmp(word,"x") == 0) mine = atom->x[index][0];
  2538. else if (strcmp(word,"y") == 0) mine = atom->x[index][1];
  2539. else if (strcmp(word,"z") == 0) mine = atom->x[index][2];
  2540. else if (strcmp(word,"vx") == 0) mine = atom->v[index][0];
  2541. else if (strcmp(word,"vy") == 0) mine = atom->v[index][1];
  2542. else if (strcmp(word,"vz") == 0) mine = atom->v[index][2];
  2543. else if (strcmp(word,"fx") == 0) mine = atom->f[index][0];
  2544. else if (strcmp(word,"fy") == 0) mine = atom->f[index][1];
  2545. else if (strcmp(word,"fz") == 0) mine = atom->f[index][2];
  2546. else error->one("Invalid atom vector in variable formula");
  2547. } else mine = vector[index*nstride];
  2548. } else mine = 0.0;
  2549. double value;
  2550. MPI_Allreduce(&mine,&value,1,MPI_DOUBLE,MPI_SUM,world);
  2551. if (tree) {
  2552. Tree *newtree = new Tree();
  2553. newtree->type = VALUE;
  2554. newtree->value = value;
  2555. newtree->left = newtree->middle = newtree->right = NULL;
  2556. treestack[ntreestack++] = newtree;
  2557. } else argstack[nargstack++] = value;
  2558. }
  2559. /* ----------------------------------------------------------------------
  2560. check if word matches an atom vector
  2561. return 1 if yes, else 0
  2562. customize by adding an atom vector:
  2563. mass,type,x,y,z,vx,vy,vz,fx,fy,fz
  2564. ------------------------------------------------------------------------- */
  2565. int Variable::is_atom_vector(char *word)
  2566. {
  2567. if (strcmp(word,"mass") == 0) return 1;
  2568. if (strcmp(word,"type") == 0) return 1;
  2569. if (strcmp(word,"x") == 0) return 1;
  2570. if (strcmp(word,"y") == 0) return 1;
  2571. if (strcmp(word,"z") == 0) return 1;
  2572. if (strcmp(word,"vx") == 0) return 1;
  2573. if (strcmp(word,"vy") == 0) return 1;
  2574. if (strcmp(word,"vz") == 0) return 1;
  2575. if (strcmp(word,"fx") == 0) return 1;
  2576. if (strcmp(word,"fy") == 0) return 1;
  2577. if (strcmp(word,"fz") == 0) return 1;
  2578. return 0;
  2579. }
  2580. /* ----------------------------------------------------------------------
  2581. process an atom vector in formula
  2582. push result onto tree
  2583. word = atom vector
  2584. customize by adding an atom vector:
  2585. mass,type,x,y,z,vx,vy,vz,fx,fy,fz
  2586. ------------------------------------------------------------------------- */
  2587. void Variable::atom_vector(char *word, Tree **tree,
  2588. Tree **treestack, int &ntreestack)
  2589. {
  2590. if (tree == NULL)
  2591. error->all("Atom vector in equal-style variable formula");
  2592. Tree *newtree = new Tree();
  2593. newtree->type = ATOMARRAY;
  2594. newtree->nstride = 3;
  2595. newtree->left = newtree->middle = newtree->right = NULL;
  2596. treestack[ntreestack++] = newtree;
  2597. if (strcmp(word,"mass") == 0) {
  2598. if (atom->rmass) {
  2599. newtree->nstride = 1;
  2600. newtree->array = atom->rmass;
  2601. } else {
  2602. newtree->type = TYPEARRAY;
  2603. newtree->array = atom->mass;
  2604. }
  2605. } else if (strcmp(word,"type") == 0) {
  2606. newtree->type = INTARRAY;
  2607. newtree->nstride = 1;
  2608. newtree->iarray = atom->type;
  2609. }
  2610. else if (strcmp(word,"x") == 0) newtree->array = &atom->x[0][0];
  2611. else if (strcmp(word,"y") == 0) newtree->array = &atom->x[0][1];
  2612. else if (strcmp(word,"z") == 0) newtree->array = &atom->x[0][2];
  2613. else if (strcmp(word,"vx") == 0) newtree->array = &atom->v[0][0];
  2614. else if (strcmp(word,"vy") == 0) newtree->array = &atom->v[0][1];
  2615. else if (strcmp(word,"vz") == 0) newtree->array = &atom->v[0][2];
  2616. else if (strcmp(word,"fx") == 0) newtree->array = &atom->f[0][0];
  2617. else if (strcmp(word,"fy") == 0) newtree->array = &atom->f[0][1];
  2618. else if (strcmp(word,"fz") == 0) newtree->array = &atom->f[0][2];
  2619. }
  2620. /* ----------------------------------------------------------------------
  2621. check if word matches a constant
  2622. return 1 if yes, else 0
  2623. customize by adding a constant: PI
  2624. ------------------------------------------------------------------------- */
  2625. int Variable::is_constant(char *word)
  2626. {
  2627. if (strcmp(word,"PI") == 0) return 1;
  2628. return 0;
  2629. }
  2630. /* ----------------------------------------------------------------------
  2631. process a constant in formula
  2632. customize by adding a constant: PI
  2633. ------------------------------------------------------------------------- */
  2634. double Variable::constant(char *word)
  2635. {
  2636. if (strcmp(word,"PI") == 0) return PI;
  2637. return 0.0;
  2638. }
  2639. /* ----------------------------------------------------------------------
  2640. read a floating point value from a string
  2641. generate an error if not a legitimate floating point value
  2642. ------------------------------------------------------------------------- */
  2643. double Variable::numeric(char *str)
  2644. {
  2645. int n = strlen(str);
  2646. for (int i = 0; i < n; i++) {
  2647. if (isdigit(str[i])) continue;
  2648. if (str[i] == '-' || str[i] == '+' || str[i] == '.') continue;
  2649. if (str[i] == 'e' || str[i] == 'E') continue;
  2650. error->all("Expected floating point parameter in variable definition");
  2651. }
  2652. return atof(str);
  2653. }
  2654. /* ----------------------------------------------------------------------
  2655. read an integer value from a string
  2656. generate an error if not a legitimate integer value
  2657. ------------------------------------------------------------------------- */
  2658. int Variable::inumeric(char *str)
  2659. {
  2660. int n = strlen(str);
  2661. for (int i = 0; i < n; i++) {
  2662. if (isdigit(str[i]) || str[i] == '-' || str[i] == '+') continue;
  2663. error->all("Expected integer parameter in variable definition");
  2664. }
  2665. return atoi(str);
  2666. }
  2667. /* ----------------------------------------------------------------------
  2668. debug routine for printing formula tree recursively
  2669. ------------------------------------------------------------------------- */
  2670. void Variable::print_tree(Tree *tree, int level)
  2671. {
  2672. printf("TREE %d: %d %g\n",level,tree->type,tree->value);
  2673. if (tree->left) print_tree(tree->left,level+1);
  2674. if (tree->middle) print_tree(tree->middle,level+1);
  2675. if (tree->right) print_tree(tree->right,level+1);
  2676. return;
  2677. }
  2678. /* ----------------------------------------------------------------------
  2679. recursive evaluation of string str
  2680. called from "if" command in input script
  2681. str is a boolean expression containing one or more items:
  2682. number = 0.0, -5.45, 2.8e-4, ...
  2683. math operation = (),x==y,x!=y,x<y,x<=y,x>y,x>=y,x&&y,x||y
  2684. ------------------------------------------------------------------------- */
  2685. double Variable::evaluate_boolean(char *str)
  2686. {
  2687. int op,opprevious;
  2688. double value1,value2;
  2689. char onechar;
  2690. char *ptr;
  2691. double argstack[MAXLEVEL];
  2692. int opstack[MAXLEVEL];
  2693. int nargstack = 0;
  2694. int nopstack = 0;
  2695. int i = 0;
  2696. int expect = ARG;
  2697. while (1) {
  2698. onechar = str[i];
  2699. // whitespace: just skip
  2700. if (isspace(onechar)) i++;
  2701. // ----------------
  2702. // parentheses: recursively evaluate contents of parens
  2703. // ----------------
  2704. else if (onechar == '(') {
  2705. if (expect == OP) error->all("Invalid Boolean syntax in if command");
  2706. expect = OP;
  2707. char *contents;
  2708. i = find_matching_paren(str,i,contents);
  2709. i++;
  2710. // evaluate contents and push on stack
  2711. argstack[nargstack++] = evaluate_boolean(contents);
  2712. delete [] contents;
  2713. // ----------------
  2714. // number: push value onto stack
  2715. // ----------------
  2716. } else if (isdigit(onechar) || onechar == '.' || onechar == '-') {
  2717. if (expect == OP) error->all("Invalid Boolean syntax in if command");
  2718. expect = OP;
  2719. // istop = end of number, including scientific notation
  2720. int istart = i++;
  2721. while (isdigit(str[i]) || str[i] == '.') i++;
  2722. if (str[i] == 'e' || str[i] == 'E') {
  2723. i++;
  2724. if (str[i] == '+' || str[i] == '-') i++;
  2725. while (isdigit(str[i])) i++;
  2726. }
  2727. int istop = i - 1;
  2728. int n = istop - istart + 1;
  2729. char *number = new char[n+1];
  2730. strncpy(number,&str[istart],n);
  2731. number[n] = '\0';
  2732. argstack[nargstack++] = atof(number);
  2733. delete [] number;
  2734. // ----------------
  2735. // Boolean operator, including end-of-string
  2736. // ----------------
  2737. } else if (strchr("<>=!&|\0",onechar)) {
  2738. if (onechar == '=') {
  2739. if (str[i+1] != '=')
  2740. error->all("Invalid Boolean syntax in if command");
  2741. op = EQ;
  2742. i++;
  2743. } else if (onechar == '!') {
  2744. if (str[i+1] == '=') {
  2745. op = NE;
  2746. i++;
  2747. } else op = NOT;
  2748. } else if (onechar == '<') {
  2749. if (str[i+1] != '=') op = LT;
  2750. else {
  2751. op = LE;
  2752. i++;
  2753. }
  2754. } else if (onechar == '>') {
  2755. if (str[i+1] != '=') op = GT;
  2756. else {
  2757. op = GE;
  2758. i++;
  2759. }
  2760. } else if (onechar == '&') {
  2761. if (str[i+1] != '&')
  2762. error->all("Invalid Boolean syntax in if command");
  2763. op = AND;
  2764. i++;
  2765. } else if (onechar == '|') {
  2766. if (str[i+1] != '|')
  2767. error->all("Invalid Boolean syntax in if command");
  2768. op = OR;
  2769. i++;
  2770. } else op = DONE;
  2771. i++;
  2772. if (op == NOT && expect == ARG) {
  2773. opstack[nopstack++] = op;
  2774. continue;
  2775. }
  2776. if (expect == ARG) error->all("Invalid Boolean syntax in if command");
  2777. expect = ARG;
  2778. // evaluate stack as deep as possible while respecting precedence
  2779. // before pushing current op onto stack
  2780. while (nopstack && precedence[opstack[nopstack-1]] >= precedence[op]) {
  2781. opprevious = opstack[--nopstack];
  2782. value2 = argstack[--nargstack];
  2783. if (opprevious != NOT) value1 = argstack[--nargstack];
  2784. if (opprevious == NOT) {
  2785. if (value2 == 0.0) argstack[nargstack++] = 1.0;
  2786. else argstack[nargstack++] = 0.0;
  2787. } else if (opprevious == EQ) {
  2788. if (value1 == value2) argstack[nargstack++] = 1.0;
  2789. else argstack[nargstack++] = 0.0;
  2790. } else if (opprevious == NE) {
  2791. if (value1 != value2) argstack[nargstack++] = 1.0;
  2792. else argstack[nargstack++] = 0.0;
  2793. } else if (opprevious == LT) {
  2794. if (value1 < value2) argstack[nargstack++] = 1.0;
  2795. else argstack[nargstack++] = 0.0;
  2796. } else if (opprevious == LE) {
  2797. if (value1 <= value2) argstack[nargstack++] = 1.0;
  2798. else argstack[nargstack++] = 0.0;
  2799. } else if (opprevious == GT) {
  2800. if (value1 > value2) argstack[nargstack++] = 1.0;
  2801. else argstack[nargstack++] = 0.0;
  2802. } else if (opprevious == GE) {
  2803. if (value1 >= value2) argstack[nargstack++] = 1.0;
  2804. else argstack[nargstack++] = 0.0;
  2805. } else if (opprevious == AND) {
  2806. if (value1 != 0.0 && value2 != 0.0) argstack[nargstack++] = 1.0;
  2807. else argstack[nargstack++] = 0.0;
  2808. } else if (opprevious == OR) {
  2809. if (value1 != 0.0 || value2 != 0.0) argstack[nargstack++] = 1.0;
  2810. else argstack[nargstack++] = 0.0;
  2811. }
  2812. }
  2813. // if end-of-string, break out of entire formula evaluation loop
  2814. if (op == DONE) break;
  2815. // push current operation onto stack
  2816. opstack[nopstack++] = op;
  2817. } else error->all("Invalid Boolean syntax in if command");
  2818. }
  2819. if (nopstack) error->all("Invalid Boolean syntax in if command");
  2820. if (nargstack != 1) error->all("Invalid Boolean syntax in if command");
  2821. return argstack[0];
  2822. }