/*! * \param[in] data Data for the current frame. * \param[in] sel Selection element being evaluated. * \param[in] g Group for which \p sel should be evaluated. * \returns 0 on success, a non-zero error code on error. * * Short-circuiting evaluation of logical AND expressions. * * Starts by evaluating the first child element in the group \p g. * The each following child element is evaluated in the intersection * of all the previous values until all children have been evaluated * or the intersection becomes empty. * The value of \p sel is set to the intersection of all the (evaluated) * child values. * * If the first child does not have an evaluation function, it is skipped * and the evaluation is started at the second child. * This happens if the first child is a constant expression and during * compilation it was detected that the evaluation group is always a subset * of the constant group * (currently, the compiler never detects this). * * This function is used as \c t_selelem::evaluate for \ref SEL_BOOLEAN * elements with \ref BOOL_AND. */ void _gmx_sel_evaluate_and(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g) { t_selelem *child; child = sel->child; /* Skip the first child if it does not have an evaluation function. */ if (!child->evaluate) { child = child->next; } /* Evaluate the first child */ { MempoolSelelemReserver reserver(child, g->isize); child->evaluate(data, child, g); gmx_ana_index_copy(sel->v.u.g, child->v.u.g, false); } child = child->next; while (child && sel->v.u.g->isize > 0) { MempoolSelelemReserver reserver(child, sel->v.u.g->isize); child->evaluate(data, child, sel->v.u.g); gmx_ana_index_intersection(sel->v.u.g, sel->v.u.g, child->v.u.g); child = child->next; } }
/*! \brief * Checks whether two position calculations should use a common base. * * \param[in] pc1 Calculation 1 to check for. * \param[in] pc2 Calculation 2 to check for. * \param[in] g1 Index group structure that contains the atoms from * \p pc1. * \param[in,out] g Working space, should have enough allocated memory to * contain the intersection of the atoms in \p pc1 and \p pc2. * \returns TRUE if the two calculations should be merged to use a common * base, FALSE otherwise. */ static bool should_merge(gmx_ana_poscalc_t *pc1, gmx_ana_poscalc_t *pc2, gmx_ana_index_t *g1, gmx_ana_index_t *g) { gmx_ana_index_t g2; /* Do not merge calculations with different mass weighting. */ if ((pc1->flags & POS_MASS) != (pc2->flags & POS_MASS)) { return FALSE; } /* Avoid messing up complete calculations. */ if ((pc1->flags & POS_COMPLWHOLE) != (pc2->flags & POS_COMPLWHOLE)) { return FALSE; } /* Find the overlap between the calculations. */ gmx_ana_index_set(&g2, pc2->b.nra, pc2->b.a, NULL, 0); gmx_ana_index_intersection(g, g1, &g2); /* Do not merge if there is no overlap. */ if (g->isize == 0) { return FALSE; } /* Full completion calculations always match if the type is correct. */ if ((pc1->flags & POS_COMPLWHOLE) && (pc2->flags & POS_COMPLWHOLE) && pc1->type == pc2->type) { return TRUE; } /* The calculations also match if the intersection consists of full * blocks. */ if (gmx_ana_index_has_full_ablocks(g, &pc1->b) && gmx_ana_index_has_full_ablocks(g, &pc2->b)) { return TRUE; } return FALSE; }
/*! * \param[in] data Data for the current frame. * \param[in] sel Selection element being evaluated. * \param[in] g Group for which \p sel should be evaluated. * \returns 0 on success, a non-zero error code on error. * * If the value type is \ref POS_VALUE, the value of the child is simply * copied to set the value of \p sel (the child subexpression should * already have been evaluated by its root). * If the value type is something else, the child is evaluated for the * group \p g, and the value of the child is then copied. * There should be only one child element. * * This function is used as \c t_selelem::evaluate for \ref SEL_SUBEXPRREF * elements. */ void _gmx_sel_evaluate_subexprref(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g) { t_selelem *expr; int i, j; if (g) { sel->child->evaluate(data, sel->child, g); } expr = sel->child; switch (sel->v.type) { case INT_VALUE: if (!g) { sel->v.nr = expr->v.nr; memcpy(sel->v.u.i, expr->v.u.i, sel->v.nr*sizeof(*sel->v.u.i)); } else { sel->v.nr = g->isize; /* Extract the values corresponding to g */ for (i = j = 0; i < g->isize; ++i, ++j) { while (sel->child->u.cgrp.index[j] < g->index[i]) { ++j; } sel->v.u.i[i] = expr->v.u.i[j]; } } break; case REAL_VALUE: if (!g) { sel->v.nr = expr->v.nr; memcpy(sel->v.u.r, expr->v.u.r, sel->v.nr*sizeof(*sel->v.u.r)); } else { sel->v.nr = g->isize; /* Extract the values corresponding to g */ for (i = j = 0; i < g->isize; ++i, ++j) { while (sel->child->u.cgrp.index[j] < g->index[i]) { ++j; } sel->v.u.r[i] = expr->v.u.r[j]; } } break; case STR_VALUE: if (!g) { sel->v.nr = expr->v.nr; memcpy(sel->v.u.s, expr->v.u.s, sel->v.nr*sizeof(*sel->v.u.s)); } else { sel->v.nr = g->isize; /* Extract the values corresponding to g */ for (i = j = 0; i < g->isize; ++i, ++j) { while (sel->child->u.cgrp.index[j] < g->index[i]) { ++j; } sel->v.u.s[i] = expr->v.u.s[j]; } } break; case POS_VALUE: /* Currently, there is no need to do anything fancy here, * but some future extensions may need a more flexible * implementation. */ gmx_ana_pos_copy(sel->v.u.p, expr->v.u.p, false); break; case GROUP_VALUE: if (!g) { gmx_ana_index_copy(sel->v.u.g, expr->v.u.g, false); } else { gmx_ana_index_intersection(sel->v.u.g, expr->v.u.g, g); } break; default: /* should not be reached */ GMX_THROW(gmx::InternalError("Invalid subexpression reference type")); } /* Store the number of values if needed */ if (sel->u.param) { sel->u.param->val.nr = sel->v.nr; if (sel->u.param->nvalptr) { *sel->u.param->nvalptr = sel->u.param->val.nr; } } }
/*! * \param[in] data Data for the current frame. * \param[in] sel Selection element being evaluated. * \param[in] g Group for which \p sel should be evaluated. * \returns 0 for success. * * Sets the value of \p sel to the intersection of \p g and \p sel->u.cgrp. * * This function can be used as \c t_selelem::evaluate for \ref SEL_CONST * elements with value type \ref GROUP_VALUE. */ void _gmx_sel_evaluate_static(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g) { gmx_ana_index_intersection(sel->v.u.g, &sel->u.cgrp, g); }