/*! * \param[in] top Not used. * \param[in] npar Not used (should be 2). * \param[in] param Method parameters (should point to \ref smparams_permute). * \param[in] data Should point to a \p t_methoddata_permute. * \returns 0 if the input permutation is valid, -1 on error. */ static void init_permute(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data) { t_methoddata_permute *d = (t_methoddata_permute *)data; int i; gmx_ana_index_reserve(&d->g, d->p.g->isize); d->n = param[1].val.nr; d->perm = param[1].val.u.i; if (d->p.nr % d->n != 0) { GMX_THROW(gmx::InconsistentInputError( gmx::formatString("The number of positions to be permuted is not divisible by %d", d->n))); } snew(d->rperm, d->n); for (i = 0; i < d->n; ++i) { d->rperm[i] = -1; } for (i = 0; i < d->n; ++i) { d->perm[i]--; if (d->perm[i] < 0 || d->perm[i] >= d->n) { GMX_THROW(gmx::InvalidInputError("Invalid permutation")); } if (d->rperm[d->perm[i]] >= 0) { GMX_THROW(gmx::InvalidInputError("Invalid permutation")); } d->rperm[d->perm[i]] = i; } }
/*! * \param[in] top Not used. * \param[in] npar Not used (should be 2). * \param[in] param Method parameters (should point to \ref smparams_permute). * \param[in] data Should point to a \p t_methoddata_permute. * \returns 0 if the input permutation is valid, -1 on error. */ static int init_permute(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data) { t_methoddata_permute *d = (t_methoddata_permute *)data; int i; gmx_ana_index_reserve(&d->g, d->p.g->isize); d->n = param[1].val.nr; d->perm = param[1].val.u.i; if (d->p.nr % d->n != 0) { fprintf(stderr, "error: the number of positions to be permuted is not divisible by %d\n", d->n); return -1; } snew(d->rperm, d->n); for (i = 0; i < d->n; ++i) { d->rperm[i] = -1; } for (i = 0; i < d->n; ++i) { d->perm[i]--; if (d->perm[i] < 0 || d->perm[i] >= d->n) { fprintf(stderr, "invalid permutation"); return -1; } if (d->rperm[d->perm[i]] >= 0) { fprintf(stderr, "invalid permutation"); return -1; } d->rperm[d->perm[i]] = i; } 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); } }