/*! \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); } }
/*! * \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 this is the first call for this frame, evaluates the child element * there should be exactly one in \p g. * The compiler has taken care that the child actually stores the evaluated * value in the value pointer of this element. * Assumes that \p g is persistent for the duration of the whole evaluation. * * This function is used as \c t_selelem::evaluate for \ref SEL_SUBEXPR * elements that have a static evaluation group, and hence do not need full * subexpression handling. */ void _gmx_sel_evaluate_subexpr_staticeval(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g) { if (sel->u.cgrp.isize == 0) { sel->child->evaluate(data, sel->child, g); sel->v.nr = sel->child->v.nr; gmx_ana_index_set(&sel->u.cgrp, g->isize, g->index, sel->u.cgrp.name, 0); } }
void SelectionTreeElement::resolveIndexGroupReference( gmx_ana_indexgrps_t *grps, int natoms) { GMX_RELEASE_ASSERT(type == SEL_GROUPREF, "Should only be called for index group reference elements"); if (grps == NULL) { std::string message = formatString( "Cannot match '%s', because index groups are not available.", name().c_str()); GMX_THROW(InconsistentInputError(message)); } gmx_ana_index_t foundGroup; std::string foundName; if (u.gref.name != NULL) { if (!gmx_ana_indexgrps_find(&foundGroup, &foundName, grps, u.gref.name)) { std::string message = formatString( "Cannot match '%s', because no such index group can be found.", name().c_str()); GMX_THROW(InconsistentInputError(message)); } } else { if (!gmx_ana_indexgrps_extract(&foundGroup, &foundName, grps, u.gref.id)) { std::string message = formatString( "Cannot match '%s', because no such index group can be found.", name().c_str()); GMX_THROW(InconsistentInputError(message)); } } if (!gmx_ana_index_check_sorted(&foundGroup)) { flags |= SEL_UNSORTED; } sfree(u.gref.name); type = SEL_CONST; gmx_ana_index_set(&u.cgrp, foundGroup.isize, foundGroup.index, foundGroup.nalloc_index); setName(foundName); if (natoms > 0) { checkIndexGroup(natoms); } }
/*! * \param[out] g Index group structure. * \param[in] ngrps Number of index groups. * \param[in] isize Array of index group sizes. * \param[in] index Array of pointers to indices of each group. * \param[in] name Array of names of the groups. * \param[in] bFree If TRUE, the \p isize, \p index and \p name arrays * are freed after they have been copied. */ void gmx_ana_indexgrps_set(gmx_ana_indexgrps_t **g, int ngrps, int *isize, atom_id **index, char **name, bool bFree) { int i; gmx_ana_indexgrps_alloc(g, ngrps); for (i = 0; i < ngrps; ++i) { gmx_ana_index_set(&(*g)->g[i], isize[i], index[i], name[i], isize[i]); } if (bFree) { sfree(isize); sfree(index); sfree(name); } }
/*! \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; }
/*! \brief * Setups the static base calculation for a position calculation. * * \param[in,out] pc Position calculation to setup the base for. */ static void setup_base(gmx_ana_poscalc_t *pc) { gmx_ana_poscalc_t *base, *pbase, *next; gmx_ana_index_t gp, g; /* Exit immediately if pc should not have a base. */ if (!can_use_base(pc)) { return; } gmx_ana_index_set(&gp, pc->b.nra, pc->b.a, NULL, 0); gmx_ana_index_clear(&g); gmx_ana_index_reserve(&g, pc->b.nra); pbase = pc; base = pc->coll->first; while (base) { /* Save the next calculation so that we can safely delete base */ next = base->next; /* Skip pc, calculations that already have a base (we should match the * base instead), as well as calculations that should not have a base. * If the above conditions are met, check whether we should do a * merge. */ if (base != pc && !base->sbase && can_use_base(base) && should_merge(pbase, base, &gp, &g)) { /* Check whether this is the first base found */ if (pbase == pc) { /* Create a real base if one is not present */ if (!base->p) { pbase = create_simple_base(base); } else { pbase = base; } /* Make it a base for pc as well */ merge_to_base(pbase, pc); pc->sbase = pbase; pbase->refcount++; } else /* This was not the first base */ { if (!base->p) { /* If it is not a real base, just make the new base as * the base for it as well. */ merge_to_base(pbase, base); base->sbase = pbase; pbase->refcount++; } else { /* If base is a real base, merge it with the new base * and delete it. */ merge_bases(pbase, base); } } gmx_ana_index_set(&gp, pbase->b.nra, pbase->b.a, NULL, 0); gmx_ana_index_reserve(&g, pc->b.nra); } /* Proceed to the next unchecked calculation */ base = next; } gmx_ana_index_deinit(&g); /* If no base was found, create one if one is required */ if (!pc->sbase && (pc->flags & POS_DYNAMIC) && (pc->flags & (POS_COMPLMAX | POS_COMPLWHOLE))) { create_simple_base(pc); } }
/*! \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); } }
void Selection::printDebugInfo(FILE *fp, int nmaxind) const { const gmx_ana_pos_t &p = data().rawPositions_; fprintf(fp, " "); printInfo(fp); fprintf(fp, " Group "); gmx_ana_index_t g; gmx_ana_index_set(&g, p.m.mapb.nra, p.m.mapb.a, 0); gmx_ana_index_dump(fp, &g, nmaxind); fprintf(fp, " Block (size=%d):", p.m.mapb.nr); if (!p.m.mapb.index) { fprintf(fp, " (null)"); } else { int n = p.m.mapb.nr; if (nmaxind >= 0 && n > nmaxind) { n = nmaxind; } for (int i = 0; i <= n; ++i) { fprintf(fp, " %d", p.m.mapb.index[i]); } if (n < p.m.mapb.nr) { fprintf(fp, " ..."); } } fprintf(fp, "\n"); int n = posCount(); if (nmaxind >= 0 && n > nmaxind) { n = nmaxind; } fprintf(fp, " RefId:"); if (!p.m.refid) { fprintf(fp, " (null)"); } else { for (int i = 0; i < n; ++i) { fprintf(fp, " %d", p.m.refid[i]); } if (n < posCount()) { fprintf(fp, " ..."); } } fprintf(fp, "\n"); fprintf(fp, " MapId:"); if (!p.m.mapid) { fprintf(fp, " (null)"); } else { for (int i = 0; i < n; ++i) { fprintf(fp, " %d", p.m.mapid[i]); } if (n < posCount()) { fprintf(fp, " ..."); } } fprintf(fp, "\n"); }