3 * This source code is part of
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
32 * \brief Implementation of functions in evaluate.h.
35 * One of the major bottlenecks for selection performance is that all the
36 * evaluation is carried out for atoms.
37 * There are several cases when the evaluation could be done for residues
38 * or molecules instead, including keywords that select by residue and
39 * cases where residue centers are used as reference positions.
40 * Implementing this would require a mechanism for recognizing whether
41 * something can be evaluated by residue/molecule instead by atom, and
42 * converting selections by residue/molecule into selections by atom
55 #include <indexutil.h>
57 #include <selection.h>
58 #include <selmethod.h>
62 #include "selcollection.h"
66 * \param[in] fp File handle to receive the output.
67 * \param[in] evalfunc Function pointer to print.
70 _gmx_sel_print_evalfunc_name(FILE *fp
, sel_evalfunc evalfunc
)
74 else if (evalfunc
== &_gmx_sel_evaluate_root
)
76 else if (evalfunc
== &_gmx_sel_evaluate_static
)
77 fprintf(fp
, "static");
78 else if (evalfunc
== &_gmx_sel_evaluate_subexpr_simple
)
79 fprintf(fp
, "subexpr_simple");
80 else if (evalfunc
== &_gmx_sel_evaluate_subexpr_staticeval
)
81 fprintf(fp
, "subexpr_staticeval");
82 else if (evalfunc
== &_gmx_sel_evaluate_subexpr
)
83 fprintf(fp
, "subexpr");
84 else if (evalfunc
== &_gmx_sel_evaluate_subexprref_simple
)
85 fprintf(fp
, "ref_simple");
86 else if (evalfunc
== &_gmx_sel_evaluate_subexprref
)
88 else if (evalfunc
== &_gmx_sel_evaluate_method
)
89 fprintf(fp
, "method");
90 else if (evalfunc
== &_gmx_sel_evaluate_modifier
)
92 else if (evalfunc
== &_gmx_sel_evaluate_not
)
94 else if (evalfunc
== &_gmx_sel_evaluate_and
)
96 else if (evalfunc
== &_gmx_sel_evaluate_or
)
98 else if (evalfunc
== &_gmx_sel_evaluate_arithmetic
)
99 fprintf(fp
, "arithmetic");
101 fprintf(fp
, "%p", (void*)(evalfunc
));
105 * \param[out] data Evaluation data structure to initialize.
106 * \param[in] mp Memory pool for intermediate evaluation values.
107 * \param[in] gall Index group with all the atoms.
108 * \param[in] top Topology structure for evaluation.
109 * \param[in] fr New frame for evaluation.
110 * \param[in] pbc New PBC information for evaluation.
113 _gmx_sel_evaluate_init(gmx_sel_evaluate_t
*data
,
114 gmx_sel_mempool_t
*mp
, gmx_ana_index_t
*gall
,
115 t_topology
*top
, t_trxframe
*fr
, t_pbc
*pbc
)
125 * Recursively initializes the flags for evaluation.
127 * \param[in,out] sel Selection element to clear.
129 * The \ref SEL_INITFRAME flag is set for \ref SEL_EXPRESSION elements whose
130 * method defines the \p init_frame callback (see sel_framefunc()), and
131 * cleared for other elements.
133 * The \ref SEL_EVALFRAME flag is cleared for all elements.
136 init_frame_eval(t_selelem
*sel
)
140 sel
->flags
&= ~(SEL_INITFRAME
| SEL_EVALFRAME
);
141 if (sel
->type
== SEL_EXPRESSION
)
143 if (sel
->u
.expr
.method
&& sel
->u
.expr
.method
->init_frame
)
145 sel
->flags
|= SEL_INITFRAME
;
148 if (sel
->child
&& sel
->type
!= SEL_SUBEXPRREF
)
150 init_frame_eval(sel
->child
);
157 * \param[in,out] sc The selection collection to evaluate.
158 * \param[in] fr Frame for which the evaluation should be carried out.
159 * \param[in] pbc PBC data, or NULL if no PBC should be used.
160 * \returns 0 on successful evaluation, a non-zero error code on error.
162 * This functions sets the global variables for topology, frame and PBC,
163 * clears some information in the selection to initialize the evaluation
164 * for a new frame, and evaluates \p sel and all the selections pointed by
165 * the \p next pointers of \p sel.
167 * This is the only function that user code should call if they want to
168 * evaluate a selection for a new frame.
171 gmx_ana_selcollection_evaluate(gmx_ana_selcollection_t
*sc
,
172 t_trxframe
*fr
, t_pbc
*pbc
)
174 gmx_sel_evaluate_t data
;
179 _gmx_sel_evaluate_init(&data
, sc
->mempool
, &sc
->gall
, sc
->top
, fr
, pbc
);
180 init_frame_eval(sc
->root
);
184 /* Clear the evaluation group of subexpressions */
185 if (sel
->child
&& sel
->child
->type
== SEL_SUBEXPR
)
187 sel
->child
->u
.cgrp
.isize
= 0;
188 /* Not strictly necessary, because the value will be overwritten
189 * during first evaluation of the subexpression anyways, but we
190 * clear the group for clarity. Note that this is _not_ done during
191 * compilation because of some additional complexities involved
192 * (see compiler.c), so it should not be relied upon in
193 * _gmx_sel_evaluate_subexpr(). */
194 if (sel
->child
->v
.type
== GROUP_VALUE
)
196 sel
->child
->v
.u
.g
->isize
= 0;
201 rc
= sel
->evaluate(&data
, sel
, NULL
);
209 /* Update selection information */
210 for (g
= 0; g
< sc
->nr
; ++g
)
212 gmx_ana_selection_t
*sel
= sc
->sel
[g
];
214 if (sel
->m
!= sel
->orgm
)
216 for (i
= 0; i
< sel
->p
.nr
; ++i
)
218 sel
->m
[i
] = sel
->orgm
[sel
->p
.m
.refid
[i
]];
219 sel
->q
[i
] = sel
->orgq
[sel
->p
.m
.refid
[i
]];
224 sel
->cfrac
= _gmx_selelem_estimate_coverfrac(sel
->selelem
);
225 sel
->avecfrac
+= sel
->cfrac
;
232 * \param[in,out] sc The selection collection to evaluate.
233 * \param[in] nframes Total number of frames.
234 * \returns 0 on successful evaluation, a non-zero error code on error.
237 gmx_ana_selcollection_evaluate_fin(gmx_ana_selcollection_t
*sc
, int nframes
)
242 for (g
= 0; g
< sc
->nr
; ++g
)
244 sel
= sc
->sel
[g
]->selelem
;
245 if (sc
->sel
[g
]->bDynamic
)
247 gmx_ana_index_copy(sc
->sel
[g
]->g
, sel
->v
.u
.g
, FALSE
);
248 sc
->sel
[g
]->g
->name
= NULL
;
249 gmx_ana_indexmap_update(&sc
->sel
[g
]->p
.m
, sc
->sel
[g
]->g
, sc
->bMaskOnly
);
250 sc
->sel
[g
]->p
.nr
= sc
->sel
[g
]->p
.m
.nr
;
253 if (sc
->sel
[g
]->bCFracDyn
)
255 sc
->sel
[g
]->avecfrac
/= nframes
;
262 * \param[in] data Data for the current frame.
263 * \param[in] sel Selection element being evaluated.
264 * \param[in] g Group for which \p sel should be evaluated.
265 * \returns 0 on success, a non-zero error code on error.
267 * Evaluates each child of \p sel in \p g.
270 _gmx_sel_evaluate_children(gmx_sel_evaluate_t
*data
, t_selelem
*sel
,
281 rc
= child
->evaluate(data
, child
, g
);
293 * \param[in] data Data for the current frame.
294 * \param[in] sel Selection element being evaluated.
295 * \param[in] g Group for which \p sel should be evaluated
296 * (not used, can be NULL).
297 * \returns 0 on success, a non-zero error code on error.
299 * Evaluates the first child element in the group defined by \p sel->u.cgrp.
300 * If \p sel->u.cgrp is empty, nothing is done.
301 * The value of \p sel is not touched (root elements do not evaluate to
304 * This function can be used as \c t_selelem::evaluate for \ref SEL_ROOT
308 _gmx_sel_evaluate_root(gmx_sel_evaluate_t
*data
, t_selelem
*sel
, gmx_ana_index_t
*g
)
312 if (sel
->u
.cgrp
.isize
== 0 || !sel
->child
->evaluate
)
317 rc
= sel
->child
->evaluate(data
, sel
->child
,
318 sel
->u
.cgrp
.isize
< 0 ? NULL
: &sel
->u
.cgrp
);
324 * \param[in] data Data for the current frame.
325 * \param[in] sel Selection element being evaluated.
326 * \param[in] g Group for which \p sel should be evaluated.
327 * \returns 0 for success.
329 * Sets the value of \p sel to the intersection of \p g and \p sel->u.cgrp.
331 * This function can be used as \c t_selelem::evaluate for \ref SEL_CONST
332 * elements with value type \ref GROUP_VALUE.
335 _gmx_sel_evaluate_static(gmx_sel_evaluate_t
*data
, t_selelem
*sel
, gmx_ana_index_t
*g
)
337 gmx_ana_index_intersection(sel
->v
.u
.g
, &sel
->u
.cgrp
, g
);
342 /*********************************************************************
343 * SUBEXPRESSION EVALUATION
344 *********************************************************************/
347 * \param[in] data Data for the current frame.
348 * \param[in] sel Selection element being evaluated.
349 * \param[in] g Group for which \p sel should be evaluated.
350 * \returns 0 on success, a non-zero error code on error.
352 * Evaluates the child element (there should be exactly one) in \p g.
353 * The compiler has taken care that the child actually stores the evaluated
354 * value in the value pointer of this element.
356 * This function is used as \c t_selelem::evaluate for \ref SEL_SUBEXPR
357 * elements that are used only once, and hence do not need full subexpression
361 _gmx_sel_evaluate_subexpr_simple(gmx_sel_evaluate_t
*data
, t_selelem
*sel
, gmx_ana_index_t
*g
)
365 if (sel
->child
->evaluate
)
367 rc
= sel
->child
->evaluate(data
, sel
->child
, g
);
373 sel
->v
.nr
= sel
->child
->v
.nr
;
378 * \param[in] data Data for the current frame.
379 * \param[in] sel Selection element being evaluated.
380 * \param[in] g Group for which \p sel should be evaluated.
381 * \returns 0 on success, a non-zero error code on error.
383 * If this is the first call for this frame, evaluates the child element
384 * there should be exactly one in \p g.
385 * The compiler has taken care that the child actually stores the evaluated
386 * value in the value pointer of this element.
387 * Assumes that \p g is persistent for the duration of the whole evaluation.
389 * This function is used as \c t_selelem::evaluate for \ref SEL_SUBEXPR
390 * elements that have a static evaluation group, and hence do not need full
391 * subexpression handling.
394 _gmx_sel_evaluate_subexpr_staticeval(gmx_sel_evaluate_t
*data
, t_selelem
*sel
, gmx_ana_index_t
*g
)
396 if (sel
->u
.cgrp
.isize
== 0)
400 rc
= sel
->child
->evaluate(data
, sel
->child
, g
);
405 sel
->v
.nr
= sel
->child
->v
.nr
;
406 gmx_ana_index_set(&sel
->u
.cgrp
, g
->isize
, g
->index
, sel
->u
.cgrp
.name
, 0);
412 * \param[in] data Data for the current frame.
413 * \param[in] sel Selection element being evaluated.
414 * \param[in] g Group for which \p sel should be evaluated.
415 * \returns 0 on success, a non-zero error code on error.
417 * Finds the part of \p g for which the subexpression
418 * has not yet been evaluated by comparing \p g to \p sel->u.cgrp.
419 * If the part is not empty, the child expression is evaluated for this
420 * part, and the results merged to the old values of the child.
421 * The value of \p sel itself is undefined after the call.
424 * The call to gmx_ana_index_difference() can take quite a lot of unnecessary
425 * time if the subexpression is evaluated either several times for the same
426 * group or for completely distinct groups.
427 * However, in the majority of cases, these situations occur when
428 * _gmx_sel_evaluate_subexpr_staticeval() can be used, so this should not be a
432 _gmx_sel_evaluate_subexpr(gmx_sel_evaluate_t
*data
, t_selelem
*sel
, gmx_ana_index_t
*g
)
434 gmx_ana_index_t gmiss
;
437 if (sel
->u
.cgrp
.isize
== 0)
440 void *old_ptr
= sel
->child
->v
.u
.ptr
;
441 int old_nalloc
= sel
->child
->v
.nalloc
;
442 _gmx_selvalue_setstore(&sel
->child
->v
, sel
->v
.u
.ptr
);
443 rc
= sel
->child
->evaluate(data
, sel
->child
, g
);
444 _gmx_selvalue_setstore_alloc(&sel
->child
->v
, old_ptr
, old_nalloc
);
449 /* We need to keep the name for the cgrp across the copy to avoid
450 * problems if g has a name set. */
451 name
= sel
->u
.cgrp
.name
;
452 gmx_ana_index_copy(&sel
->u
.cgrp
, g
, FALSE
);
453 sel
->u
.cgrp
.name
= name
;
458 /* We allocate some extra memory here to avoid some computation. */
459 rc
= _gmx_sel_mempool_alloc_group(data
->mp
, &gmiss
, g
->isize
);
464 gmx_ana_index_difference(&gmiss
, g
, &sel
->u
.cgrp
);
465 if (gmiss
.isize
== 0)
467 _gmx_sel_mempool_free_group(data
->mp
, &gmiss
);
472 rc
= _gmx_selelem_mempool_reserve(sel
->child
, gmiss
.isize
);
477 /* Evaluate the missing values for the child */
478 rc
= sel
->child
->evaluate(data
, sel
->child
, &gmiss
);
483 /* Merge the missing values to the existing ones. */
484 if (sel
->v
.type
== GROUP_VALUE
)
486 gmx_ana_index_merge(sel
->v
.u
.g
, sel
->child
->v
.u
.g
, sel
->v
.u
.g
);
492 i
= sel
->u
.cgrp
.isize
- 1;
494 /* TODO: This switch is kind of ugly, but it may be difficult to
495 * do this portably without C++ templates. */
499 for (k
= sel
->u
.cgrp
.isize
+ gmiss
.isize
- 1; k
>= 0; k
--)
501 if (i
< 0 || (j
>= 0 && sel
->u
.cgrp
.index
[i
] < gmiss
.index
[j
]))
503 sel
->v
.u
.i
[k
] = sel
->v
.u
.i
[j
--];
507 sel
->v
.u
.i
[k
] = sel
->child
->v
.u
.i
[i
--];
513 for (k
= sel
->u
.cgrp
.isize
+ gmiss
.isize
- 1; k
>= 0; k
--)
515 if (i
< 0 || (j
>= 0 && sel
->u
.cgrp
.index
[i
] < gmiss
.index
[j
]))
517 sel
->v
.u
.r
[k
] = sel
->v
.u
.r
[j
--];
521 sel
->v
.u
.r
[k
] = sel
->child
->v
.u
.r
[i
--];
527 for (k
= sel
->u
.cgrp
.isize
+ gmiss
.isize
- 1; k
>= 0; k
--)
529 if (i
< 0 || (j
>= 0 && sel
->u
.cgrp
.index
[i
] < gmiss
.index
[j
]))
531 sel
->v
.u
.s
[k
] = sel
->v
.u
.s
[j
--];
535 sel
->v
.u
.s
[k
] = sel
->child
->v
.u
.s
[i
--];
541 /* TODO: Implement this */
542 gmx_impl("position subexpressions not implemented properly");
547 gmx_bug("internal error");
551 gmx_ana_index_merge(&sel
->u
.cgrp
, &sel
->u
.cgrp
, &gmiss
);
552 _gmx_selelem_mempool_release(sel
->child
);
553 _gmx_sel_mempool_free_group(data
->mp
, &gmiss
);
559 * \param[in] data Data for the current frame.
560 * \param[in] sel Selection element being evaluated.
561 * \param[in] g Group for which \p sel should be evaluated.
562 * \returns 0 for success.
564 * Sets the value pointers of the child and its child to point to the same
565 * memory as the value pointer of this element to avoid copying, and then
566 * evaluates evaluates the child.
568 * This function is used as \c t_selelem:evaluate for \ref SEL_SUBEXPRREF
569 * elements for which the \ref SEL_SUBEXPR does not have other references.
572 _gmx_sel_evaluate_subexprref_simple(gmx_sel_evaluate_t
*data
, t_selelem
*sel
, gmx_ana_index_t
*g
)
578 _gmx_selvalue_setstore(&sel
->child
->v
, sel
->v
.u
.ptr
);
579 _gmx_selvalue_setstore_alloc(&sel
->child
->child
->v
, sel
->v
.u
.ptr
,
580 sel
->child
->child
->v
.nalloc
);
581 rc
= sel
->child
->evaluate(data
, sel
->child
, g
);
587 sel
->v
.nr
= sel
->child
->v
.nr
;
590 sel
->u
.param
->val
.nr
= sel
->v
.nr
;
591 if (sel
->u
.param
->nvalptr
)
593 *sel
->u
.param
->nvalptr
= sel
->u
.param
->val
.nr
;
600 * \param[in] data Data for the current frame.
601 * \param[in] sel Selection element being evaluated.
602 * \param[in] g Group for which \p sel should be evaluated.
603 * \returns 0 on success, a non-zero error code on error.
605 * If the value type is \ref POS_VALUE, the value of the child is simply
606 * copied to set the value of \p sel (the child subexpression should
607 * already have been evaluated by its root).
608 * If the value type is something else, the child is evaluated for the
609 * group \p g, and the value of the child is then copied.
610 * There should be only one child element.
612 * This function is used as \c t_selelem::evaluate for \ref SEL_SUBEXPRREF
616 _gmx_sel_evaluate_subexprref(gmx_sel_evaluate_t
*data
, t_selelem
*sel
, gmx_ana_index_t
*g
)
625 rc
= sel
->child
->evaluate(data
, sel
->child
, g
);
637 sel
->v
.nr
= expr
->v
.nr
;
638 memcpy(sel
->v
.u
.i
, expr
->v
.u
.i
, sel
->v
.nr
*sizeof(*sel
->v
.u
.i
));
642 sel
->v
.nr
= g
->isize
;
643 /* Extract the values corresponding to g */
644 for (i
= j
= 0; i
< g
->isize
; ++i
, ++j
)
646 while (sel
->child
->u
.cgrp
.index
[j
] < g
->index
[i
])
650 sel
->v
.u
.i
[i
] = expr
->v
.u
.i
[j
];
658 sel
->v
.nr
= expr
->v
.nr
;
659 memcpy(sel
->v
.u
.r
, expr
->v
.u
.r
, sel
->v
.nr
*sizeof(*sel
->v
.u
.r
));
663 sel
->v
.nr
= g
->isize
;
664 /* Extract the values corresponding to g */
665 for (i
= j
= 0; i
< g
->isize
; ++i
, ++j
)
667 while (sel
->child
->u
.cgrp
.index
[j
] < g
->index
[i
])
671 sel
->v
.u
.r
[i
] = expr
->v
.u
.r
[j
];
679 sel
->v
.nr
= expr
->v
.nr
;
680 memcpy(sel
->v
.u
.s
, expr
->v
.u
.s
, sel
->v
.nr
*sizeof(*sel
->v
.u
.s
));
684 sel
->v
.nr
= g
->isize
;
685 /* Extract the values corresponding to g */
686 for (i
= j
= 0; i
< g
->isize
; ++i
, ++j
)
688 while (sel
->child
->u
.cgrp
.index
[j
] < g
->index
[i
])
692 sel
->v
.u
.s
[i
] = expr
->v
.u
.s
[j
];
698 /* Currently, there is no need to do anything fancy here,
699 * but some future extensions may need a more flexible
701 gmx_ana_pos_copy(sel
->v
.u
.p
, expr
->v
.u
.p
, FALSE
);
707 gmx_ana_index_copy(sel
->v
.u
.g
, expr
->v
.u
.g
, FALSE
);
711 gmx_ana_index_intersection(sel
->v
.u
.g
, expr
->v
.u
.g
, g
);
715 default: /* should not be reached */
716 gmx_bug("invalid subexpression reference type");
719 /* Store the number of values if needed */
722 sel
->u
.param
->val
.nr
= sel
->v
.nr
;
723 if (sel
->u
.param
->nvalptr
)
725 *sel
->u
.param
->nvalptr
= sel
->u
.param
->val
.nr
;
731 /********************************************************************
732 * METHOD EXPRESSION EVALUATION
733 ********************************************************************/
736 * \param[in] data Data for the current frame.
737 * \param[in] sel Selection element being evaluated.
738 * \param[in] g Group for which \p sel should be evaluated.
739 * \returns 0 on success, a non-zero error code on error.
741 * Evaluates each child of a \ref SEL_EXPRESSION element.
742 * The value of \p sel is not touched.
744 * This function is not used as \c t_selelem::evaluate,
745 * but is used internally.
748 _gmx_sel_evaluate_method_params(gmx_sel_evaluate_t
*data
, t_selelem
*sel
, gmx_ana_index_t
*g
)
756 if (child
->evaluate
&& !(child
->flags
& SEL_EVALFRAME
))
758 if (child
->flags
& SEL_ATOMVAL
)
760 rc
= child
->evaluate(data
, child
, g
);
764 rc
= child
->evaluate(data
, child
, NULL
);
765 child
->flags
|= SEL_EVALFRAME
;
778 * \param[in] data Data for the current frame.
779 * \param[in] sel Selection element being evaluated.
780 * \param[in] g Group for which \p sel should be evaluated.
781 * \returns 0 on success, a non-zero error code on error.
783 * Evaluates all child selections (using _gmx_sel_evaluate_method_params())
784 * to evaluate any parameter values.
785 * If this is the first time this expression is evaluated for
786 * the frame, sel_framefunc() callback is called if one is provided.
787 * If a reference position calculation has been initialized for this element,
788 * the positions are also updated, and sel_updatefunc_pos() is used to
789 * evaluate the value. Otherwise, sel_updatefunc() is used.
791 * This function is used as \c t_selelem::evaluate for \ref SEL_EXPRESSION
795 _gmx_sel_evaluate_method(gmx_sel_evaluate_t
*data
, t_selelem
*sel
, gmx_ana_index_t
*g
)
799 rc
= _gmx_sel_evaluate_method_params(data
, sel
, g
);
804 if (sel
->flags
& SEL_INITFRAME
)
806 rc
= sel
->u
.expr
.method
->init_frame(data
->top
, data
->fr
, data
->pbc
,
808 sel
->flags
&= ~SEL_INITFRAME
;
816 gmx_ana_poscalc_update(sel
->u
.expr
.pc
, sel
->u
.expr
.pos
, g
,
817 data
->fr
, data
->pbc
);
818 rc
= sel
->u
.expr
.method
->pupdate(data
->top
, data
->fr
, data
->pbc
,
819 sel
->u
.expr
.pos
, &sel
->v
,
824 rc
= sel
->u
.expr
.method
->update(data
->top
, data
->fr
, data
->pbc
, g
,
825 &sel
->v
, sel
->u
.expr
.mdata
);
831 * \param[in] data Data for the current frame.
832 * \param[in] sel Selection element being evaluated.
833 * \param[in] g Group for which \p sel should be evaluated.
834 * \returns 0 on success, a non-zero error code on error.
836 * Evaluates all child selections (using _gmx_sel_evaluate_method_params())
837 * to evaluate any parameter values.
838 * If this is the first time this expression is evaluated for
839 * the frame, sel_framefunc() callback is called if one is provided.
840 * The modifier is then evaluated using sel_updatefunc_pos().
842 * This function is used as \c t_selelem::evaluate for \ref SEL_MODIFIER
846 _gmx_sel_evaluate_modifier(gmx_sel_evaluate_t
*data
, t_selelem
*sel
, gmx_ana_index_t
*g
)
850 rc
= _gmx_sel_evaluate_method_params(data
, sel
, g
);
855 if (sel
->flags
& SEL_INITFRAME
)
857 rc
= sel
->u
.expr
.method
->init_frame(data
->top
, data
->fr
, data
->pbc
,
859 sel
->flags
&= ~SEL_INITFRAME
;
865 if (sel
->child
->v
.type
!= POS_VALUE
)
867 gmx_bug("non-position valued modifiers not implemented");
870 rc
= sel
->u
.expr
.method
->pupdate(data
->top
, data
->fr
, data
->pbc
,
872 &sel
->v
, sel
->u
.expr
.mdata
);
877 /********************************************************************
878 * BOOLEAN EXPRESSION EVALUATION
879 ********************************************************************/
882 * \param[in] data Data for the current frame.
883 * \param[in] sel Selection element being evaluated.
884 * \param[in] g Group for which \p sel should be evaluated.
885 * \returns 0 on success, a non-zero error code on error.
887 * Evaluates the child element (there should be only one) in the group
888 * \p g, and then sets the value of \p sel to the complement of the
891 * This function is used as \c t_selelem::evaluate for \ref SEL_BOOLEAN
892 * elements with \ref BOOL_NOT.
895 _gmx_sel_evaluate_not(gmx_sel_evaluate_t
*data
, t_selelem
*sel
, gmx_ana_index_t
*g
)
899 rc
= _gmx_selelem_mempool_reserve(sel
->child
, g
->isize
);
902 rc
= sel
->child
->evaluate(data
, sel
->child
, g
);
908 gmx_ana_index_difference(sel
->v
.u
.g
, g
, sel
->child
->v
.u
.g
);
909 _gmx_selelem_mempool_release(sel
->child
);
914 * \param[in] data Data for the current frame.
915 * \param[in] sel Selection element being evaluated.
916 * \param[in] g Group for which \p sel should be evaluated.
917 * \returns 0 on success, a non-zero error code on error.
919 * Short-circuiting evaluation of logical AND expressions.
921 * Starts by evaluating the first child element in the group \p g.
922 * The each following child element is evaluated in the intersection
923 * of all the previous values until all children have been evaluated
924 * or the intersection becomes empty.
925 * The value of \p sel is set to the intersection of all the (evaluated)
928 * If the first child does not have an evaluation function, it is skipped
929 * and the evaluation is started at the second child.
930 * This happens if the first child is a constant expression and during
931 * compilation it was detected that the evaluation group is always a subset
932 * of the constant group
933 * (currently, the compiler never detects this).
935 * This function is used as \c t_selelem::evaluate for \ref SEL_BOOLEAN
936 * elements with \ref BOOL_AND.
939 _gmx_sel_evaluate_and(gmx_sel_evaluate_t
*data
, t_selelem
*sel
, gmx_ana_index_t
*g
)
945 /* Skip the first child if it does not have an evaluation function. */
946 if (!child
->evaluate
)
950 rc
= _gmx_selelem_mempool_reserve(child
, g
->isize
);
953 rc
= child
->evaluate(data
, child
, g
);
959 gmx_ana_index_copy(sel
->v
.u
.g
, child
->v
.u
.g
, FALSE
);
960 _gmx_selelem_mempool_release(child
);
962 while (child
&& sel
->v
.u
.g
->isize
> 0)
964 rc
= _gmx_selelem_mempool_reserve(child
, sel
->v
.u
.g
->isize
);
967 rc
= child
->evaluate(data
, child
, sel
->v
.u
.g
);
973 gmx_ana_index_intersection(sel
->v
.u
.g
, sel
->v
.u
.g
, child
->v
.u
.g
);
974 _gmx_selelem_mempool_release(child
);
981 * \param[in] data Data for the current frame.
982 * \param[in] sel Selection element being evaluated.
983 * \param[in] g Group for which \p sel should be evaluated.
984 * \returns 0 on success, a non-zero error code on error.
986 * Short-circuiting evaluation of logical OR expressions.
988 * Starts by evaluating the first child element in the group \p g.
989 * For each subsequent child, finds the part of \p g that is not
990 * included the value of any previous child, and evaluates the child
991 * in that group until the last child is evaluated or all of \p g
992 * is included in some child value.
993 * The value of \p sel is set to the union of all the (evaluated)
996 * If the first child does not have an evaluation function, its value is
997 * used without evaluation.
998 * This happens if the first child is a constant expression, the selection
999 * has been compiled, and the evaluation group is the same for each frame.
1000 * In this case, the compiler has taken care of that the child value is a
1001 * subset of \p g, making it unnecessary to evaluate it.
1003 * This function is used as \c t_selelem::evaluate for \ref SEL_BOOLEAN
1004 * elements with \ref BOOL_OR.
1007 _gmx_sel_evaluate_or(gmx_sel_evaluate_t
*data
, t_selelem
*sel
, gmx_ana_index_t
*g
)
1010 gmx_ana_index_t tmp
, tmp2
;
1014 if (child
->evaluate
)
1016 rc
= _gmx_selelem_mempool_reserve(child
, g
->isize
);
1019 rc
= child
->evaluate(data
, child
, g
);
1025 gmx_ana_index_partition(sel
->v
.u
.g
, &tmp
, g
, child
->v
.u
.g
);
1026 _gmx_selelem_mempool_release(child
);
1030 gmx_ana_index_partition(sel
->v
.u
.g
, &tmp
, g
, child
->v
.u
.g
);
1032 child
= child
->next
;
1033 while (child
&& tmp
.isize
> 0)
1036 rc
= _gmx_selelem_mempool_reserve(child
, tmp
.isize
);
1039 rc
= child
->evaluate(data
, child
, &tmp
);
1045 gmx_ana_index_partition(&tmp
, &tmp2
, &tmp
, child
->v
.u
.g
);
1046 _gmx_selelem_mempool_release(child
);
1047 sel
->v
.u
.g
->isize
+= tmp
.isize
;
1048 tmp
.isize
= tmp2
.isize
;
1049 tmp
.index
= tmp2
.index
;
1050 child
= child
->next
;
1052 gmx_ana_index_sort(sel
->v
.u
.g
);
1057 /********************************************************************
1058 * ARITHMETIC EVALUATION
1059 ********************************************************************/
1062 * \param[in] data Data for the current frame.
1063 * \param[in] sel Selection element being evaluated.
1064 * \param[in] g Group for which \p sel should be evaluated.
1065 * \returns 0 on success, a non-zero error code on error.
1068 _gmx_sel_evaluate_arithmetic(gmx_sel_evaluate_t
*data
, t_selelem
*sel
,
1071 t_selelem
*left
, *right
;
1073 real lval
, rval
=0., val
=0.;
1081 _gmx_selvalue_setstore(&left
->v
, sel
->v
.u
.ptr
);
1084 rc
= _gmx_selelem_mempool_reserve(right
, g
->isize
);
1091 else if (right
&& right
->mempool
)
1093 _gmx_selvalue_setstore(&right
->v
, sel
->v
.u
.ptr
);
1095 rc
= _gmx_sel_evaluate_children(data
, sel
, g
);
1097 n
= (sel
->flags
& SEL_SINGLEVAL
) ? 1 : g
->isize
;
1099 for (i
= i1
= i2
= 0; i
< n
; ++i
)
1101 lval
= left
->v
.u
.r
[i1
];
1102 if (sel
->u
.arith
.type
!= ARITH_NEG
)
1104 rval
= right
->v
.u
.r
[i2
];
1106 switch (sel
->u
.arith
.type
)
1108 case ARITH_PLUS
: val
= lval
+ rval
; break;
1109 case ARITH_MINUS
: val
= lval
- rval
; break;
1110 case ARITH_NEG
: val
= -lval
; break;
1111 case ARITH_MULT
: val
= lval
* rval
; break;
1112 case ARITH_DIV
: val
= lval
/ rval
; break;
1113 case ARITH_EXP
: val
= pow(lval
, rval
); break;
1115 sel
->v
.u
.r
[i
] = val
;
1116 if (!(left
->flags
& SEL_SINGLEVAL
))
1120 if (sel
->u
.arith
.type
!= ARITH_NEG
&& !(right
->flags
& SEL_SINGLEVAL
))
1128 _gmx_selvalue_setstore(&left
->v
, NULL
);
1131 _gmx_selelem_mempool_release(right
);
1134 else if (right
&& right
->mempool
)
1136 _gmx_selvalue_setstore(&right
->v
, NULL
);