/*! * \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 * Initializes position calculation using the maximum possible input index. * * \param[in,out] pc Position calculation data structure. * \param[in] g Maximum index group for the calculation. * \param[in] bBase Whether \p pc will be used as a base or not. * * \p bBase affects on how the \p pc->gmax field is initialized. */ static void set_poscalc_maxindex(gmx_ana_poscalc_t *pc, gmx_ana_index_t *g, bool bBase) { e_index_t ptype; ptype = index_type_for_poscalc(pc->type); gmx_ana_index_make_block(&pc->b, pc->coll->top, g, ptype, pc->flags & POS_COMPLWHOLE); /* Set the type to POS_ATOM if the calculation in fact is such. */ if (pc->b.nr == pc->b.nra) { pc->type = POS_ATOM; pc->flags &= ~(POS_MASS | POS_COMPLMAX | POS_COMPLWHOLE); } /* Set the POS_COMPLWHOLE flag if the calculation in fact always uses * complete residues and molecules. */ if (!(pc->flags & POS_COMPLWHOLE) && (!(pc->flags & POS_DYNAMIC) || (pc->flags & POS_COMPLMAX)) && (pc->type == POS_RES || pc->type == POS_MOL) && gmx_ana_index_has_complete_elems(g, ptype, pc->coll->top)) { pc->flags &= ~POS_COMPLMAX; pc->flags |= POS_COMPLWHOLE; } /* Setup the gmax field */ if ((pc->flags & POS_COMPLWHOLE) && !bBase && pc->b.nra > g->isize) { gmx_ana_index_copy(&pc->gmax, g, TRUE); sfree(pc->gmax.name); pc->gmax.name = NULL; } else { gmx_ana_index_set(&pc->gmax, pc->b.nra, pc->b.a, NULL, 0); } }
/*! * See sel_updatefunc() for description of the parameters. * \p data is not used. * * Copies \p g to \p out->u.g. */ static int evaluate_all(t_topology *top, t_trxframe *fr, t_pbc *pbc, gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data) { gmx_ana_index_copy(out->u.g, g, FALSE); return 0; }
/*! * \param[out] dest Destination index groups. * \param[in] src Source index groups. * * A deep copy is made for all fields, including the group names. */ void gmx_ana_indexgrps_clone(gmx_ana_indexgrps_t **dest, gmx_ana_indexgrps_t *src) { int g; gmx_ana_indexgrps_alloc(dest, src->nr); for (g = 0; g < src->nr; ++g) { gmx_ana_index_copy(&(*dest)->g[g], &src->g[g], TRUE); } }
/*! * \param[out] dest Output structure. * \param[in] src Input index groups. * \param[in] n Number of the group to extract. * \returns TRUE if \p n is a valid group in \p src, FALSE otherwise. */ bool gmx_ana_indexgrps_extract(gmx_ana_index_t *dest, gmx_ana_indexgrps_t *src, int n) { if (n < 0 || n >= src->nr) { dest->isize = 0; return FALSE; } gmx_ana_index_copy(dest, &src->g[n], TRUE); return TRUE; }
/*! * \param[out] dest Output structure. * \param[in] src Input index groups. * \param[in] n Number of the group to extract. * \returns true if \p n is a valid group in \p src, false otherwise. */ bool gmx_ana_indexgrps_extract(gmx_ana_index_t *dest, gmx_ana_indexgrps_t *src, int n) { if (n < 0 || n >= src->nr) { dest->isize = 0; return false; } gmx_ana_index_copy(dest, &src->g[n], true); return true; }
void SelectionData::restoreOriginalPositions(const t_topology *top) { if (isDynamic()) { gmx_ana_pos_t &p = rawPositions_; gmx_ana_index_copy(p.g, rootElement().v.u.g, false); gmx_ana_indexmap_update(&p.m, p.g, hasFlag(gmx::efSelection_DynamicMask)); p.nr = p.m.nr; refreshMassesAndCharges(top); } }
/*! * \param[out] dest Output structure. * \param[out] destName Receives the name of the group if found. * \param[in] src Input index groups. * \param[in] n Number of the group to extract. * \returns true if \p n is a valid group in \p src, false otherwise. */ bool gmx_ana_indexgrps_extract(gmx_ana_index_t *dest, std::string *destName, gmx_ana_indexgrps_t *src, int n) { destName->clear(); if (n < 0 || n >= src->nr) { dest->isize = 0; return false; } if (destName != NULL) { *destName = src->names[n]; } gmx_ana_index_copy(dest, &src->g[n], true); return true; }
void gmx_ana_index_union_unsorted(gmx_ana_index_t *dest, gmx_ana_index_t *a, gmx_ana_index_t *b) { if (gmx_ana_index_check_sorted(b)) { gmx_ana_index_union(dest, a, b); } else { gmx_ana_index_t tmp; gmx_ana_index_copy(&tmp, b, true); gmx_ana_index_sort(&tmp); gmx_ana_index_remove_duplicates(&tmp); gmx_ana_index_union(dest, a, &tmp); gmx_ana_index_deinit(&tmp); } }
/*! * \param[out] dest1 Output group 1 (will equal \p g). * \param[out] dest2 Output group 2 (will equal \p src - \p g). * \param[in] src Group to be partitioned. * \param[in] g One partition. * * \pre \p g is a subset of \p src and both sets are sorted * \pre \p dest1 has allocated storage to store \p src * \post \p dest1 == \p g * \post \p dest2 == \p src - \p g * * No storage should be allocated for \p dest2; after the call, * \p dest2->index points to the memory allocated for \p dest1 * (to a part that is not used by \p dest1). * * The calculation can be performed in-place by setting \p dest1 equal to * \p src. */ void gmx_ana_index_partition(gmx_ana_index_t *dest1, gmx_ana_index_t *dest2, gmx_ana_index_t *src, gmx_ana_index_t *g) { int i, j, k; dest2->index = dest1->index + g->isize; dest2->isize = src->isize - g->isize; for (i = g->isize-1, j = src->isize-1, k = dest2->isize-1; i >= 0; --i, --j) { while (j >= 0 && src->index[j] != g->index[i]) { dest2->index[k--] = src->index[j--]; } } while (j >= 0) { dest2->index[k--] = src->index[j--]; } gmx_ana_index_copy(dest1, g, 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 on success, a non-zero error code on error. * * Finds the part of \p g for which the subexpression * has not yet been evaluated by comparing \p g to \p sel->u.cgrp. * If the part is not empty, the child expression is evaluated for this * part, and the results merged to the old values of the child. * The value of \p sel itself is undefined after the call. * * \todo * The call to gmx_ana_index_difference() can take quite a lot of unnecessary * time if the subexpression is evaluated either several times for the same * group or for completely distinct groups. * However, in the majority of cases, these situations occur when * _gmx_sel_evaluate_subexpr_staticeval() can be used, so this should not be a * major problem. */ void _gmx_sel_evaluate_subexpr(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g) { gmx_ana_index_t gmiss; MempoolGroupReserver gmissreserver(data->mp); if (sel->u.cgrp.isize == 0) { { SelelemTemporaryValueAssigner assigner(sel->child, sel); sel->child->evaluate(data, sel->child, g); } /* We need to keep the name for the cgrp across the copy to avoid * problems if g has a name set. */ char *name = sel->u.cgrp.name; gmx_ana_index_copy(&sel->u.cgrp, g, false); sel->u.cgrp.name = name; gmiss.isize = 0; } else { gmissreserver.reserve(&gmiss, g->isize); gmx_ana_index_difference(&gmiss, g, &sel->u.cgrp); } if (gmiss.isize > 0) { MempoolSelelemReserver reserver(sel->child, gmiss.isize); /* Evaluate the missing values for the child */ sel->child->evaluate(data, sel->child, &gmiss); /* Merge the missing values to the existing ones. */ if (sel->v.type == GROUP_VALUE) { gmx_ana_index_merge(sel->v.u.g, sel->child->v.u.g, sel->v.u.g); } else { int i, j, k; i = sel->u.cgrp.isize - 1; j = gmiss.isize - 1; /* TODO: This switch is kind of ugly, but it may be difficult to * do this portably without C++ templates. */ switch (sel->v.type) { case INT_VALUE: for (k = sel->u.cgrp.isize + gmiss.isize - 1; k >= 0; k--) { if (i < 0 || (j >= 0 && sel->u.cgrp.index[i] < gmiss.index[j])) { sel->v.u.i[k] = sel->v.u.i[j--]; } else { sel->v.u.i[k] = sel->child->v.u.i[i--]; } } break; case REAL_VALUE: for (k = sel->u.cgrp.isize + gmiss.isize - 1; k >= 0; k--) { if (i < 0 || (j >= 0 && sel->u.cgrp.index[i] < gmiss.index[j])) { sel->v.u.r[k] = sel->v.u.r[j--]; } else { sel->v.u.r[k] = sel->child->v.u.r[i--]; } } break; case STR_VALUE: for (k = sel->u.cgrp.isize + gmiss.isize - 1; k >= 0; k--) { if (i < 0 || (j >= 0 && sel->u.cgrp.index[i] < gmiss.index[j])) { sel->v.u.s[k] = sel->v.u.s[j--]; } else { sel->v.u.s[k] = sel->child->v.u.s[i--]; } } break; case POS_VALUE: /* TODO: Implement this */ GMX_THROW(gmx::NotImplementedError("position subexpressions not implemented properly")); case NO_VALUE: case GROUP_VALUE: GMX_THROW(gmx::InternalError("Invalid subexpression type")); } } gmx_ana_index_merge(&sel->u.cgrp, &sel->u.cgrp, &gmiss); } }
/*! * See sel_updatefunc() for description of the parameters. * \p data is not used. * * Copies \p g to \p out->u.g. */ static void evaluate_all(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */, gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */) { gmx_ana_index_copy(out->u.g, g, false); }