SelectionCollection::Impl::Impl(gmx_ana_poscalc_coll_t *pcc) : _options("selection", "Common selection control"), _debugLevel(0), _grps(NULL) { _sc.root = NULL; _sc.nvars = 0; _sc.varstrs = NULL; _sc.top = NULL; gmx_ana_index_clear(&_sc.gall); _sc.pcc = pcc; _sc.mempool = NULL; _sc.symtab = NULL; // TODO: This is not exception-safe if any called function throws. if (_sc.pcc == NULL) { int rc = gmx_ana_poscalc_coll_create(&_sc.pcc); if (rc != 0) { // TODO: A more reasonable error GMX_THROW(InternalError("Failed to create position calculation collection")); } _flags.set(Impl::efOwnPositionCollection); } _gmx_sel_symtab_create(&_sc.symtab); gmx_ana_selmethod_register_defaults(_sc.symtab); }
/*! * \param[out] selp Pointer to receive a pointer to the created selection * element (set to NULL on error). * \param[in] method Keyword selection method to evaluate. * \param[in] param Parameter that gives the group to evaluate \p method in. * \param[in] scanner Scanner data structure. * \returns 0 on success, non-zero error code on error. * * Creates a \ref SEL_EXPRESSION selection element (pointer put in \c *selp) * that evaluates the keyword method given by \p method in the group given by * \p param. */ int _gmx_sel_init_keyword_evaluator(t_selelem **selp, gmx_ana_selmethod_t *method, t_selexpr_param *param, void *scanner) { t_selelem *sel; t_methoddata_kweval *data; gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner); char buf[1024]; sprintf(buf, "In evaluation of '%s'", method->name); gmx::MessageStringContext context(errors, buf); if ((method->flags & (SMETH_SINGLEVAL | SMETH_VARNUMVAL)) || method->outinit || method->pupdate) { _gmx_selexpr_free_params(param); GMX_ERROR(gmx::eeInternalError, "Unsupported keyword method for arbitrary group evaluation"); } *selp = NULL; sel = _gmx_selelem_create(SEL_EXPRESSION); _gmx_selelem_set_method(sel, method, scanner); snew(data, 1); data->kwmethod = sel->u.expr.method; data->kwmdata = sel->u.expr.mdata; gmx_ana_index_clear(&data->g); snew(sel->u.expr.method, 1); memcpy(sel->u.expr.method, data->kwmethod, sizeof(gmx_ana_selmethod_t)); sel->u.expr.method->flags |= SMETH_VARNUMVAL; sel->u.expr.method->init_data = NULL; sel->u.expr.method->set_poscoll = NULL; sel->u.expr.method->init = method->init ? &init_kweval : NULL; sel->u.expr.method->outinit = &init_output_kweval; sel->u.expr.method->free = &free_data_kweval; sel->u.expr.method->init_frame = method->init_frame ? &init_frame_kweval : NULL; sel->u.expr.method->update = &evaluate_kweval; sel->u.expr.method->pupdate = NULL; sel->u.expr.method->nparams = asize(smparams_kweval); sel->u.expr.method->param = smparams_kweval; _gmx_selelem_init_method_params(sel, scanner); sel->u.expr.mdata = data; sel->u.expr.method->param[0].val.u.g = &data->g; sfree(param->name); param->name = NULL; if (!_gmx_sel_parse_params(param, sel->u.expr.method->nparams, sel->u.expr.method->param, sel, scanner)) { _gmx_selelem_free(sel); return -1; } *selp = sel; return 0; }
/*! * \param[in] g Index group structure. * * The pointer \p g is not freed. */ void gmx_ana_index_deinit(gmx_ana_index_t *g) { if (g->nalloc_index > 0) { sfree(g->index); } gmx_ana_index_clear(g); }
SelectionCollection::Impl::Impl() : maxAtomIndex_(0), debugLevel_(0), bExternalGroupsSet_(false), grps_(NULL) { sc_.nvars = 0; sc_.varstrs = NULL; sc_.top = NULL; gmx_ana_index_clear(&sc_.gall); sc_.mempool = NULL; sc_.symtab.reset(new SelectionParserSymbolTable); gmx_ana_selmethod_register_defaults(sc_.symtab.get()); }
/*! * \param[in,out] val Value structure to allocate. * \param[in] n Maximum number of values needed. * \returns Zero on success. * * Reserves memory for the values within \p val to store at least \p n values, * of the type specified in the \p val structure. * * If the type is \ref POS_VALUE or \ref GROUP_VALUE, memory is reserved for * the data structures, but no memory is reserved inside these newly allocated * data structures. * Similarly, for \ref STR_VALUE values, the pointers are set to NULL. * For other values, the memory is uninitialized. */ int _gmx_selvalue_reserve(gmx_ana_selvalue_t *val, int n) { int i; if (val->nalloc == -1) { return 0; } if (!val->u.ptr || val->nalloc < n) { switch (val->type) { case INT_VALUE: srenew(val->u.i, n); break; case REAL_VALUE: srenew(val->u.r, n); break; case STR_VALUE: srenew(val->u.s, n); for (i = val->nalloc; i < n; ++i) { val->u.s[i] = NULL; } break; case POS_VALUE: srenew(val->u.p, n); for (i = val->nalloc; i < n; ++i) { gmx_ana_pos_clear(&val->u.p[i]); } break; case GROUP_VALUE: srenew(val->u.g, n); for (i = val->nalloc; i < n; ++i) { gmx_ana_index_clear(&val->u.g[i]); } break; case NO_VALUE: break; } val->nalloc = n; } return 0; }
/*! * \param[out] scp Pointer to a newly allocated empty selection collection. * \param[in] pcc Position calculation data structure to use for selection * position evaluation. * \returns 0 on success. */ int gmx_ana_selcollection_create(gmx_ana_selcollection_t **scp, gmx_ana_poscalc_coll_t *pcc) { gmx_ana_selcollection_t *sc; snew(sc, 1); sc->rpost = NULL; sc->spost = NULL; sc->selstr = NULL; sc->root = NULL; sc->nr = 0; sc->sel = NULL; sc->top = NULL; gmx_ana_index_clear(&sc->gall); sc->pcc = pcc; _gmx_sel_symtab_create(&sc->symtab); *scp = sc; return 0; }
/*! \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); } }