A bit more modular selection position handling.
[gromacs/qmmm-gamess-us.git] / src / gmxlib / selection / selelem.c
blob5b41535ec3216e28a6a5e3d7416f4a5cdb1f4cfb
1 /*
3 * This source code is part of
5 * G R O M A C S
7 * GROningen MAchine for Chemical Simulations
9 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11 * Copyright (c) 2001-2009, The GROMACS development team,
12 * check out http://www.gromacs.org for more information.
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * If you want to redistribute modifications, please consider that
20 * scientific software is very special. Version control is crucial -
21 * bugs must be traceable. We will be happy to consider code for
22 * inclusion in the official distribution, but derived work must not
23 * be called official GROMACS. Details are found in the README & COPYING
24 * files - if they are missing, get the official version at www.gromacs.org.
26 * To help us fund GROMACS development, we humbly ask that you cite
27 * the papers on the package - you can find them in the top README file.
29 * For more info, check our website at http://www.gromacs.org
31 /*! \internal \file
32 * \brief Implementation of functions in selelem.h.
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
38 #include <smalloc.h>
40 #include <indexutil.h>
41 #include <poscalc.h>
42 #include <position.h>
43 #include <selmethod.h>
45 #include "evaluate.h"
46 #include "keywords.h"
47 #include "selelem.h"
49 /*!
50 * \param[in] sel Selection for which the string is requested
51 * \returns Pointer to a string that corresponds to \p sel->type.
53 * The return value points to a string constant and should not be \p free'd.
55 * The function returns NULL if \p sel->type is not one of the valid values.
57 const char *
58 _gmx_selelem_type_str(t_selelem *sel)
60 switch (sel->type)
62 case SEL_CONST: return "CONST";
63 case SEL_EXPRESSION: return "EXPR";
64 case SEL_BOOLEAN: return "BOOL";
65 case SEL_ROOT: return "ROOT";
66 case SEL_SUBEXPR: return "SUBEXPR";
67 case SEL_SUBEXPRREF: return "REF";
68 case SEL_MODIFIER: return "MODIFIER";
70 return NULL;
73 /*!
74 * \param[in] val Value structore for which the string is requested.
75 * \returns Pointer to a string that corresponds to \p val->type,
76 * NULL if the type value is invalid.
78 * The return value points to a string constant and should not be \p free'd.
80 const char *
81 _gmx_sel_value_type_str(gmx_ana_selvalue_t *val)
83 switch (val->type)
85 case NO_VALUE: return "NONE";
86 case INT_VALUE: return "INT";
87 case REAL_VALUE: return "REAL";
88 case STR_VALUE: return "STR";
89 case POS_VALUE: return "VEC";
90 case GROUP_VALUE: return "GROUP";
92 return NULL;
95 /*! \copydoc _gmx_selelem_type_str() */
96 const char *
97 _gmx_selelem_boolean_type_str(t_selelem *sel)
99 switch (sel->u.boolt)
101 case BOOL_NOT: return "NOT"; break;
102 case BOOL_AND: return "AND"; break;
103 case BOOL_OR: return "OR"; break;
104 case BOOL_XOR: return "XOR"; break;
106 return NULL;
110 * \param[in] type Type of selection element to allocate.
111 * \returns Pointer to the newly allocated and initialized element.
113 * \c t_selelem::type is set to \p type,
114 * \c t_selelem::v::type is set to \ref GROUP_VALUE for boolean and comparison
115 * expressions and \ref NO_VALUE for others,
116 * \ref SEL_ALLOCVAL is set for non-root elements (\ref SEL_ALLOCDATA is also
117 * set for \ref SEL_BOOLEAN elements),
118 * and \c t_selelem::refcount is set to one.
119 * All the pointers are set to NULL.
121 t_selelem *
122 _gmx_selelem_create(e_selelem_t type)
124 t_selelem *sel;
126 snew(sel, 1);
127 sel->name = NULL;
128 sel->type = type;
129 sel->flags = (type != SEL_ROOT) ? SEL_ALLOCVAL : 0;
130 if (type == SEL_BOOLEAN)
132 sel->v.type = GROUP_VALUE;
133 sel->flags |= SEL_ALLOCDATA;
135 else
137 sel->v.type = NO_VALUE;
139 _gmx_selvalue_clear(&sel->v);
140 sel->evaluate = NULL;
141 sel->child = NULL;
142 sel->next = NULL;
143 sel->refcount = 1;
145 return sel;
149 * \param[in,out] sel Selection element to set the type for.
150 * \param[in] vtype Value type for the selection element.
151 * \returns 0 on success, EINVAL if the value type is invalid.
153 * If the new type is \ref GROUP_VALUE or \ref POS_VALUE, the
154 * \ref SEL_ALLOCDATA flag is also set.
156 * This function should only be called at most once for each element,
157 * preferably right after calling _gmx_selelem_create().
160 _gmx_selelem_set_vtype(t_selelem *sel, e_selvalue_t vtype)
162 if (sel->type == SEL_BOOLEAN && vtype != GROUP_VALUE)
164 gmx_bug("internal error");
165 return EINVAL;
167 if (sel->v.type != NO_VALUE && vtype != sel->v.type)
169 gmx_call("_gmx_selelem_set_vtype() called more than once");
170 return EINVAL;
172 sel->v.type = vtype;
173 if (vtype == GROUP_VALUE || vtype == POS_VALUE)
175 sel->flags |= SEL_ALLOCDATA;
177 return 0;
181 * \param[in] sel Selection to free.
183 void
184 _gmx_selelem_free_values(t_selelem *sel)
186 int i, n;
188 if ((sel->flags & SEL_ALLOCDATA) && sel->v.u.ptr)
190 /* The number of position/group structures is constant, so the
191 * backup of using sel->v.nr should work for them.
192 * For strings, we report an error if we don't know the allocation
193 * size here. */
194 n = (sel->v.nalloc > 0) ? sel->v.nalloc : sel->v.nr;
195 switch (sel->v.type)
197 case STR_VALUE:
198 if (sel->v.nalloc == 0)
200 gmx_bug("SEL_ALLOCDATA should only be set for allocated STR_VALUE values");
201 break;
203 for (i = 0; i < n; ++i)
205 sfree(sel->v.u.s[i]);
207 break;
208 case POS_VALUE:
209 for (i = 0; i < n; ++i)
211 gmx_ana_pos_deinit(&sel->v.u.p[i]);
213 break;
214 case GROUP_VALUE:
215 for (i = 0; i < n; ++i)
217 gmx_ana_index_deinit(&sel->v.u.g[i]);
219 break;
220 default: /* No special handling for other types */
221 break;
224 if (sel->flags & SEL_ALLOCVAL)
226 sfree(sel->v.u.ptr);
228 _gmx_selvalue_setstore(&sel->v, NULL);
232 * \param[in] sel Selection to free.
234 void
235 _gmx_selelem_free_exprdata(t_selelem *sel)
237 int i;
239 if (sel->type == SEL_EXPRESSION || sel->type == SEL_MODIFIER)
241 /* Free method data */
242 if (sel->u.expr.mdata)
244 if (sel->u.expr.method && sel->u.expr.method->free)
246 sel->u.expr.method->free(sel->u.expr.mdata);
248 sfree(sel->u.expr.mdata);
249 sel->u.expr.mdata = NULL;
251 /* Free the method itself */
252 if (sel->u.expr.method)
254 /* If the method has not yet been initialized, we must free the
255 * memory allocated for parameter values here. */
256 if (!(sel->flags & SEL_METHODINIT))
258 for (i = 0; i < sel->u.expr.method->nparams; ++i)
260 gmx_ana_selparam_t *param = &sel->u.expr.method->param[i];
262 if ((param->flags & (SPAR_VARNUM | SPAR_ATOMVAL))
263 && param->val.type != GROUP_VALUE
264 && param->val.type != POS_VALUE)
266 /* We don't need to check for enum values here, because
267 * SPAR_ENUMVAL cannot be combined with the flags
268 * required above. If it ever will be, this results
269 * in a double free within this function, which should
270 * be relatively easy to debug.
272 if (param->val.type == STR_VALUE)
274 int j;
276 for (j = 0; j < param->val.nr; ++j)
278 sfree(param->val.u.s[j]);
281 sfree(param->val.u.ptr);
285 /* And even if it is, the arrays allocated for enum values need
286 * to be freed. */
287 for (i = 0; i < sel->u.expr.method->nparams; ++i)
289 gmx_ana_selparam_t *param = &sel->u.expr.method->param[i];
291 if (param->flags & SPAR_ENUMVAL)
293 sfree(param->val.u.ptr);
297 sfree(sel->u.expr.method->param);
298 sfree(sel->u.expr.method);
299 sel->u.expr.method = NULL;
301 /* Free position data */
302 if (sel->u.expr.pos)
304 gmx_ana_pos_free(sel->u.expr.pos);
305 sel->u.expr.pos = NULL;
307 /* Free position calculation data */
308 if (sel->u.expr.pc)
310 gmx_ana_poscalc_free(sel->u.expr.pc);
311 sel->u.expr.pc = NULL;
317 * \param[in] sel Selection to free.
319 * Decrements \ref t_selelem::refcount "sel->refcount" and frees the
320 * memory allocated for \p sel and all its children if the reference count
321 * reaches zero.
323 void
324 _gmx_selelem_free(t_selelem *sel)
326 t_selelem *child, *prev;
328 /* Decrement the reference counter and do nothing if references remain */
329 sel->refcount--;
330 if (sel->refcount > 0)
332 return;
335 /* Free the children */
336 child = sel->child;
337 while (child)
339 prev = child;
340 child = child->next;
341 _gmx_selelem_free(prev);
344 /* Free value storage */
345 _gmx_selelem_free_values(sel);
347 /* Free other storage */
348 _gmx_selelem_free_exprdata(sel);
349 if (sel->type == SEL_SUBEXPR || sel->type == SEL_ROOT
350 || (sel->type == SEL_CONST && sel->v.type == GROUP_VALUE))
352 gmx_ana_index_deinit(&sel->u.cgrp);
355 /* Free temporary compiler data if present */
356 _gmx_selelem_free_compiler_data(sel);
358 sfree(sel);
362 * \param[in] first First selection to free.
364 * Frees \p first and all selections accessible through the
365 * \ref t_selelem::next "first->next" pointer.
367 void
368 _gmx_selelem_free_chain(t_selelem *first)
370 t_selelem *child, *prev;
372 child = first;
373 while (child)
375 prev = child;
376 child = child->next;
377 _gmx_selelem_free(prev);
381 /*! \brief
382 * Writes out a human-readable name for the evaluation function.
384 * \param[in] fp File handle to receive the output.
385 * \param[in] sel Selection element for which the evaluation function is printed.
387 static void
388 print_evaluation_func(FILE *fp, t_selelem *sel)
390 fprintf(fp, " eval=");
391 if (!sel->evaluate)
392 fprintf(fp, "none");
393 else if (sel->evaluate == &_gmx_sel_evaluate_root)
394 fprintf(fp, "root");
395 else if (sel->evaluate == &_gmx_sel_evaluate_static)
396 fprintf(fp, "static");
397 else if (sel->evaluate == &_gmx_sel_evaluate_subexpr_pass)
398 fprintf(fp, "subexpr_pass");
399 else if (sel->evaluate == &_gmx_sel_evaluate_subexpr)
400 fprintf(fp, "subexpr");
401 else if (sel->evaluate == &_gmx_sel_evaluate_subexprref_pass)
402 fprintf(fp, "ref_pass");
403 else if (sel->evaluate == &_gmx_sel_evaluate_subexprref)
404 fprintf(fp, "ref");
405 else if (sel->evaluate == &_gmx_sel_evaluate_method)
406 fprintf(fp, "method");
407 else if (sel->evaluate == &_gmx_sel_evaluate_modifier)
408 fprintf(fp, "mod");
409 else if (sel->evaluate == &_gmx_sel_evaluate_not)
410 fprintf(fp, "not");
411 else if (sel->evaluate == &_gmx_sel_evaluate_and)
412 fprintf(fp, "and");
413 else if (sel->evaluate == &_gmx_sel_evaluate_or)
414 fprintf(fp, "or");
415 else
416 fprintf(fp, "%p", (void*)(sel->evaluate));
420 * \param[in] fp File handle to receive the output.
421 * \param[in] sel Root of the selection subtree to print.
422 * \param[in] bValues If TRUE, the evaluated values of selection elements
423 * are printed as well.
424 * \param[in] level Indentation level, starting from zero.
426 void
427 _gmx_selelem_print_tree(FILE *fp, t_selelem *sel, bool bValues, int level)
429 t_selelem *child;
430 int i;
432 fprintf(fp, "%*c %s %s", level*2+1, '*',
433 _gmx_selelem_type_str(sel), _gmx_sel_value_type_str(&sel->v));
434 if (sel->name)
436 fprintf(fp, " \"%s\"", sel->name);
438 fprintf(fp, " flg=");
439 if (sel->flags & SEL_FLAGSSET)
441 fprintf(fp, "s");
443 if (sel->flags & SEL_SINGLEVAL)
445 fprintf(fp, "S");
447 if (sel->flags & SEL_ATOMVAL)
449 fprintf(fp, "A");
451 if (sel->flags & SEL_VARNUMVAL)
453 fprintf(fp, "V");
455 if (sel->flags & SEL_DYNAMIC)
457 fprintf(fp, "D");
459 if (!(sel->flags & SEL_VALFLAGMASK))
461 fprintf(fp, "0");
463 if (sel->type == SEL_CONST)
465 if (sel->v.type == INT_VALUE)
467 fprintf(fp, " %d", sel->v.u.i[0]);
469 else if (sel->v.type == REAL_VALUE)
471 fprintf(fp, " %f", sel->v.u.r[0]);
473 else if (sel->v.type == GROUP_VALUE)
475 gmx_ana_index_t *g = sel->v.u.g;
476 if (!g || g->isize == 0)
477 g = &sel->u.cgrp;
478 fprintf(fp, " (%d atoms)", g->isize);
481 else if (sel->type == SEL_BOOLEAN)
483 fprintf(fp, " %s", _gmx_selelem_boolean_type_str(sel));
485 else if (sel->type == SEL_EXPRESSION
486 && sel->u.expr.method->name == sm_compare.name)
488 _gmx_selelem_print_compare_info(fp, sel->u.expr.mdata);
490 if (sel->evaluate)
492 print_evaluation_func(fp, sel);
494 if (sel->refcount > 1)
496 fprintf(fp, " refc=%d", sel->refcount);
498 if (!(sel->flags & SEL_ALLOCVAL))
500 fprintf(fp, " (ext. output)");
502 fprintf(fp, "\n");
504 if ((sel->type == SEL_CONST && sel->v.type == GROUP_VALUE) || sel->type == SEL_ROOT)
506 gmx_ana_index_t *g = sel->v.u.g;
507 if (!g || g->isize == 0 || sel->evaluate != NULL)
509 g = &sel->u.cgrp;
511 if (g->isize > 0)
513 fprintf(fp, "%*c group:", level*2+1, ' ');
514 if (g->isize <= 20)
516 for (i = 0; i < g->isize; ++i)
518 fprintf(fp, " %d", g->index[i] + 1);
521 else
523 fprintf(fp, " %d atoms", g->isize);
525 fprintf(fp, "\n");
528 else if (sel->type == SEL_EXPRESSION)
530 if (sel->u.expr.pc)
532 fprintf(fp, "%*c COM", level*2+3, '*');
533 fprintf(fp, "\n");
537 if (bValues && sel->type != SEL_CONST && sel->type != SEL_ROOT && sel->v.u.ptr)
539 fprintf(fp, "%*c value: ", level*2+1, ' ');
540 switch (sel->v.type)
542 case POS_VALUE:
543 fprintf(fp, "(%f, %f, %f)",
544 sel->v.u.p->x[0][XX], sel->v.u.p->x[0][YY], sel->v.u.p->x[0][ZZ]);
545 break;
546 case GROUP_VALUE:
547 fprintf(fp, "%d atoms", sel->v.u.g->isize);
548 if (sel->v.u.g->isize < 20)
550 if (sel->v.u.g->isize > 0)
552 fprintf(fp, ":");
554 for (i = 0; i < sel->v.u.g->isize; ++i)
556 fprintf(fp, " %d", sel->v.u.g->index[i] + 1);
559 break;
560 default:
561 fprintf(fp, "???");
562 break;
564 fprintf(fp, "\n");
567 /* Print the subexpressions with one more level of indentation */
568 child = sel->child;
569 while (child)
571 if (!(sel->type == SEL_SUBEXPRREF && child->type == SEL_SUBEXPR))
573 _gmx_selelem_print_tree(fp, child, bValues, level+1);
575 child = child->next;
580 * \param[in] root Root of the subtree to query.
581 * \returns TRUE if \p root or any any of its elements require topology
582 * information, FALSE otherwise.
584 bool
585 _gmx_selelem_requires_top(t_selelem *root)
587 t_selelem *child;
589 if (root->type == SEL_EXPRESSION || root->type == SEL_MODIFIER)
591 if (root->u.expr.method && (root->u.expr.method->flags & SMETH_REQTOP))
593 return TRUE;
595 if (root->u.expr.pc && gmx_ana_poscalc_requires_top(root->u.expr.pc))
597 return TRUE;
600 child = root->child;
601 while (child)
603 if (_gmx_selelem_requires_top(child))
605 return TRUE;
607 child = child->next;
609 return FALSE;