/*! * \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. * * Evaluates the child element (there should be only one) in the group * \p g, and then sets the value of \p sel to the complement of the * child value. * * This function is used as \c t_selelem::evaluate for \ref SEL_BOOLEAN * elements with \ref BOOL_NOT. */ void _gmx_sel_evaluate_not(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g) { MempoolSelelemReserver reserver(sel->child, g->isize); sel->child->evaluate(data, sel->child, g); gmx_ana_index_difference(sel->v.u.g, g, sel->child->v.u.g); }
/*! \brief * Merges a calculation into another calculation such that the new calculation * can be used as a base. * * \param[in,out] base Base calculation to merge to. * \param[in,out] pc Position calculation to merge to \p base. * * After the call, \p base can be used as a base for \p pc (or any calculation * that used it as a base). * It is assumed that any overlap between \p base and \p pc is in complete * blocks, i.e., that the merge is possible. */ static void merge_to_base(gmx_ana_poscalc_t *base, gmx_ana_poscalc_t *pc) { gmx_ana_index_t gp, gb, g; int isize, bnr; int i, j, bi, bj, bo; gmx_ana_index_set(&gp, pc->b.nra, pc->b.a, NULL, 0); gmx_ana_index_set(&gb, base->b.nra, base->b.a, NULL, 0); isize = gmx_ana_index_difference_size(&gp, &gb); if (isize > 0) { gmx_ana_index_clear(&g); gmx_ana_index_reserve(&g, base->b.nra + isize); /* Find the new blocks */ gmx_ana_index_difference(&g, &gp, &gb); /* Count the blocks in g */ i = bi = bnr = 0; while (i < g.isize) { while (pc->b.a[pc->b.index[bi]] != g.index[i]) { ++bi; } i += pc->b.index[bi+1] - pc->b.index[bi]; ++bnr; ++bi; } /* Merge the atoms into a temporary structure */ gmx_ana_index_merge(&g, &gb, &g); /* Merge the blocks */ srenew(base->b.index, base->b.nr + bnr + 1); i = g.isize - 1; bi = base->b.nr - 1; bj = pc->b.nr - 1; bo = base->b.nr + bnr - 1; base->b.index[bo+1] = i + 1; while (bo >= 0) { if (bi < 0 || base->b.a[base->b.index[bi+1]-1] != g.index[i]) { i -= pc->b.index[bj+1] - pc->b.index[bj]; --bj; } else { if (bj >= 0 && pc->b.a[pc->b.index[bj+1]-1] == g.index[i]) { --bj; } i -= base->b.index[bi+1] - base->b.index[bi]; --bi; } base->b.index[bo] = i + 1; --bo; } base->b.nr += bnr; base->b.nalloc_index += bnr; sfree(base->b.a); base->b.nra = g.isize; base->b.a = g.index; base->b.nalloc_a = g.isize; /* Refresh the gmax field */ gmx_ana_index_set(&base->gmax, base->b.nra, base->b.a, NULL, 0); } }
/*! * \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); } }