/* Function: p7_oprofile_MPIUnpack() * Synopsis: Unpacks an OPROFILE from an MPI buffer. * Incept: MSF, Wed Oct 21, 2009 [Janelia] * * Purpose: Unpack a newly allocated OPROFILE from MPI packed buffer * <buf>, starting from position <*pos>, where the total length * of the buffer in bytes is <n>. * * Caller may or may not already know what alphabet the OPROFILE * is expected to be in. A reference to the current * alphabet is passed in <abc>. If the alphabet is unknown, * pass <*abc = NULL>, and when the OPROFILE is received, an * appropriate new alphabet object is allocated and passed * back to the caller via <*abc>. If the alphabet is * already known, <*abc> is that alphabet, and the new * OPROFILE's alphabet type is verified to agree with it. This * mechanism allows an application to let the first OPROFILE * determine the alphabet type for the application, while * still keeping the alphabet under the application's scope * of control. * * Returns: <eslOK> on success. <*pos> is updated to the position of * the next element in <buf> to unpack (if any). <*ret_om> * contains a newly allocated OPROFILE, which the caller is * responsible for free'ing. If <*abc> was passed as * <NULL>, it now points to an <ESL_ALPHABET> object that * was allocated here; caller is responsible for free'ing * this. * * Returns <eslEINCOMPAT> if the OPROFILE is in a different * alphabet than <*abc> said to expect. In this case, * <*abc> is unchanged, <*buf> and <*nalloc> may have been * changed, and <*ret_om> is <NULL>. * * Throws: <eslESYS> on an MPI call failure. <eslEMEM> on allocation failure. * In either case, <*ret_om> is <NULL>, and the state of <buf> * and <*pos> is undefined and should be considered to be corrupted. */ int p7_oprofile_MPIUnpack(char *buf, int n, int *pos, MPI_Comm comm, ESL_ALPHABET **abc, P7_OPROFILE **ret_om) { int status; int M, K, atype; int len; int x; int Q4, Q8, Q16; int vsz = sizeof(__m128i); P7_OPROFILE *om = NULL; if (MPI_Unpack(buf, n, pos, &M, 1, MPI_INT, comm) != 0) ESL_XEXCEPTION(eslESYS, "mpi unpack failed"); if (MPI_Unpack(buf, n, pos, &atype, 1, MPI_INT, comm) != 0) ESL_XEXCEPTION(eslESYS, "mpi unpack failed"); /* Set or verify the alphabet */ if (*abc == NULL) { /* still unknown: set it, pass control of it back to caller */ if ((*abc = esl_alphabet_Create(atype)) == NULL) { status = eslEMEM; goto ERROR; } } else { /* already known: check it */ if ((*abc)->type != atype) { status = eslEINCOMPAT; goto ERROR; } } Q4 = p7O_NQF(M); Q8 = p7O_NQW(M); Q16 = p7O_NQB(M); if ((om = p7_oprofile_Create(M, *abc)) == NULL) { status = eslEMEM; goto ERROR; } om->M = M; K = (*abc)->Kp; /* model configuration */ if (MPI_Unpack(buf, n, pos, &om->L, 1, MPI_INT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); if (MPI_Unpack(buf, n, pos, &om->mode, 1, MPI_INT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); if (MPI_Unpack(buf, n, pos, &om->nj, 1, MPI_FLOAT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); /* MSV Filter information */ if (MPI_Unpack(buf, n, pos, &om->tbm_b, 1, MPI_CHAR, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); if (MPI_Unpack(buf, n, pos, &om->tec_b, 1, MPI_CHAR, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); if (MPI_Unpack(buf, n, pos, &om->tjb_b, 1, MPI_CHAR, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); if (MPI_Unpack(buf, n, pos, &om->scale_b, 1, MPI_FLOAT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); if (MPI_Unpack(buf, n, pos, &om->base_b, 1, MPI_CHAR, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); if (MPI_Unpack(buf, n, pos, &om->bias_b, 1, MPI_CHAR, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); for (x = 0; x < K; x++) if (MPI_Unpack(buf, n, pos, om->rbv[x], vsz*Q16, MPI_CHAR, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); /* Viterbi Filter information */ if (MPI_Unpack(buf, n, pos, &om->scale_w, 1, MPI_FLOAT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); if (MPI_Unpack(buf, n, pos, &om->base_w, 1, MPI_SHORT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); if (MPI_Unpack(buf, n, pos, &om->ddbound_w, 1, MPI_SHORT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); if (MPI_Unpack(buf, n, pos, &om->ncj_roundoff, 1, MPI_FLOAT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); if (MPI_Unpack(buf, n, pos, om->twv, 8*vsz*Q8, MPI_CHAR, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); for (x = 0; x < p7O_NXSTATES; x++) if (MPI_Unpack(buf, n, pos, om->xw[x], p7O_NXTRANS, MPI_SHORT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); for (x = 0; x < K; x++) if (MPI_Unpack(buf, n, pos, om->rwv[x], vsz*Q8, MPI_CHAR, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); /* Forward/Backward information */ if (MPI_Unpack(buf, n, pos, om->tfv, 8*vsz*Q4, MPI_CHAR, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); for (x = 0; x < p7O_NXSTATES; x++) if (MPI_Unpack(buf, n, pos, om->xf[x], p7O_NXTRANS, MPI_FLOAT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); for (x = 0; x < K; x++) if (MPI_Unpack(buf, n, pos, om->rfv[x], vsz*Q4, MPI_CHAR, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); /* Forward/Backward information */ if (MPI_Unpack(buf, n, pos, om->offs, p7_NOFFSETS, MPI_LONG_LONG_INT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); if (MPI_Unpack(buf, n, pos, &om->roff, 1, MPI_LONG_LONG_INT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); if (MPI_Unpack(buf, n, pos, &om->eoff, 1, MPI_LONG_LONG_INT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); /* Annotation information */ if (MPI_Unpack(buf, n, pos, &len, 1, MPI_INT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); if (len > 0) { ESL_ALLOC(om->name, len); if (MPI_Unpack(buf, n, pos, om->name, len, MPI_CHAR, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); om->name[len-1] = '\0'; } if (MPI_Unpack(buf, n, pos, &len, 1, MPI_INT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); if (len > 0) { ESL_ALLOC(om->acc, len); if (MPI_Unpack(buf, n, pos, om->acc, len, MPI_CHAR, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); om->acc[len-1] = '\0'; } if (MPI_Unpack(buf, n, pos, &len, 1, MPI_INT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); if (len > 0) { ESL_ALLOC(om->desc, len); if (MPI_Unpack(buf, n, pos, om->desc, len, MPI_CHAR, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); om->desc[len-1] = '\0'; } if (MPI_Unpack(buf, n, pos, &len, 1, MPI_INT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); if (len > 0) { ESL_ALLOC(om->rf, len); if (MPI_Unpack(buf, n, pos, om->rf, len, MPI_CHAR, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); om->rf[len-1] = '\0'; } if (MPI_Unpack(buf, n, pos, &len, 1, MPI_INT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); if (len > 0) { ESL_ALLOC(om->mm, len); if (MPI_Unpack(buf, n, pos, om->mm, len, MPI_CHAR, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); om->mm[len-1] = '\0'; } if (MPI_Unpack(buf, n, pos, &len, 1, MPI_INT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); if (len > 0) { ESL_ALLOC(om->cs, len); if (MPI_Unpack(buf, n, pos, om->cs, len, MPI_CHAR, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); om->cs[len-1] = '\0'; } if (MPI_Unpack(buf, n, pos, &len, 1, MPI_INT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); if (len > 0) { ESL_ALLOC(om->consensus, len); if (MPI_Unpack(buf, n, pos, om->consensus, len, MPI_CHAR, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); om->consensus[len-1] = '\0'; } if (MPI_Unpack(buf, n, pos, om->evparam, p7_NEVPARAM, MPI_FLOAT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); if (MPI_Unpack(buf, n, pos, om->cutoff, p7_NCUTOFFS, MPI_FLOAT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); if (MPI_Unpack(buf, n, pos, om->compo, p7_MAXABET, MPI_FLOAT, comm) != 0) ESL_EXCEPTION(eslESYS, "mpi unpack failed"); *ret_om = om; return eslOK; ERROR: if (om != NULL) p7_oprofile_Destroy(om); return status; }
/* Function: p7_oprofile_MPIPack() * Synopsis: Packs an OPROFILE into MPI buffer. * Incept: MSF, Wed Oct 21, 2009 [Janelia] * * Purpose: Packs OPROFILE <om> into an MPI packed message buffer <buf> * of length <n> bytes, starting at byte position <*position>, * for MPI communicator <comm>. * * The caller must know that <buf>'s allocation of <n> * bytes is large enough to append the packed OPROFILE at * position <*pos>. This typically requires a call to * <p7_oprofile_MPIPackSize()> first, and reallocation if * needed. * * Returns: <eslOK> on success; <buf> now contains the * packed <om>, and <*position> is set to the byte * immediately following the last byte of the OPROFILE * in <buf>. * * Throws: <eslESYS> if an MPI call fails; or <eslEMEM> if the * buffer's length <n> was overflowed in trying to pack * <msa> into <buf>. In either case, the state of * <buf> and <*position> is undefined, and both should * be considered to be corrupted. */ int p7_oprofile_MPIPack(P7_OPROFILE *om, char *buf, int n, int *pos, MPI_Comm comm) { int K = om->abc->Kp; int atype = om->abc->type; int len; int x; int Q4 = p7O_NQF(om->M); int Q8 = p7O_NQW(om->M); int Q16 = p7O_NQB(om->M); int vsz = sizeof(vector float); /* model configuration */ if (MPI_Pack(&om->M, 1, MPI_INT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (MPI_Pack(&atype, 1, MPI_INT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (MPI_Pack(&om->L, 1, MPI_INT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (MPI_Pack(&om->mode, 1, MPI_INT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (MPI_Pack(&om->nj, 1, MPI_FLOAT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); /* MSV Filter information */ if (MPI_Pack(&om->tbm_b, 1, MPI_CHAR, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (MPI_Pack(&om->tec_b, 1, MPI_CHAR, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (MPI_Pack(&om->tjb_b, 1, MPI_CHAR, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (MPI_Pack(&om->scale_b, 1, MPI_FLOAT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (MPI_Pack(&om->base_b, 1, MPI_CHAR, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (MPI_Pack(&om->bias_b, 1, MPI_CHAR, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); for (x = 0; x < K; x++) if (MPI_Pack( om->rbv[x], vsz*Q16, MPI_CHAR, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); /* Viterbi Filter information */ if (MPI_Pack(&om->scale_w, 1, MPI_FLOAT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (MPI_Pack(&om->base_w, 1, MPI_SHORT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (MPI_Pack(&om->ddbound_w, 1, MPI_SHORT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (MPI_Pack(&om->ncj_roundoff, 1, MPI_FLOAT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (MPI_Pack( om->twv, 8*vsz*Q8, MPI_CHAR, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); for (x = 0; x < p7O_NXSTATES; x++) if (MPI_Pack( om->xw[x], p7O_NXTRANS, MPI_SHORT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); for (x = 0; x < K; x++) if (MPI_Pack( om->rwv[x], vsz*Q8, MPI_CHAR, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); /* Forward/Backward information */ if (MPI_Pack( om->tfv, 8*vsz*Q4, MPI_CHAR, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); for (x = 0; x < p7O_NXSTATES; x++) if (MPI_Pack( om->xf[x], p7O_NXTRANS, MPI_FLOAT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); for (x = 0; x < K; x++) if (MPI_Pack( om->rfv[x], vsz*Q4, MPI_CHAR, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); /* Forward/Backward information */ if (MPI_Pack( om->offs, p7_NOFFSETS, MPI_LONG_LONG_INT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (MPI_Pack(&om->roff, 1, MPI_LONG_LONG_INT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (MPI_Pack(&om->eoff, 1, MPI_LONG_LONG_INT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); /* Annotation information */ len = (om->name != NULL) ? strlen(om->name)+1 : 0; if (MPI_Pack(&len, 1, MPI_INT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (len > 0) if (MPI_Pack( om->name, len, MPI_CHAR, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); len = (om->acc != NULL) ? strlen(om->acc)+1 : 0; if (MPI_Pack(&len, 1, MPI_INT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (len > 0) if (MPI_Pack( om->acc, len, MPI_CHAR, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); len = (om->desc != NULL) ? strlen(om->desc)+1 : 0; if (MPI_Pack(&len, 1, MPI_INT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (len > 0) if (MPI_Pack( om->desc, len, MPI_CHAR, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); len = (om->rf != NULL) ? strlen(om->rf)+1 : 0; if (MPI_Pack(&len, 1, MPI_INT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (len > 0) if (MPI_Pack( om->rf, len, MPI_CHAR, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); len = (om->cs != NULL) ? strlen(om->cs)+1 : 0; if (MPI_Pack(&len, 1, MPI_INT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (len > 0) if (MPI_Pack( om->cs, len, MPI_CHAR, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); len = (om->consensus != NULL) ? strlen(om->consensus)+1 : 0; if (MPI_Pack(&len, 1, MPI_INT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (len > 0) if (MPI_Pack( om->consensus, len, MPI_CHAR, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (MPI_Pack( om->evparam, p7_NEVPARAM, MPI_FLOAT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (MPI_Pack( om->cutoff, p7_NCUTOFFS, MPI_FLOAT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (MPI_Pack( om->compo, p7_MAXABET, MPI_FLOAT, buf, n, pos, comm) != 0) ESL_EXCEPTION(eslESYS, "pack failed"); if (*pos > n) ESL_EXCEPTION(eslEMEM, "buffer overflow"); return eslOK; }
/* Function: p7_SSVFilter_longtarget() * Synopsis: Finds windows with SSV scores above some threshold (vewy vewy fast, in limited precision) * * Purpose: Calculates an approximation of the SSV (single ungapped diagonal) * score for regions of sequence <dsq> of length <L> residues, using * optimized profile <om>, and a preallocated one-row DP matrix <ox>, * and captures the positions at which such regions exceed the score * required to be significant in the eyes of the calling function, * which depends on the <bg> and <p> (usually p=0.02 for nhmmer). * Note that this variant performs only SSV computations, never * passing through the J state - the score required to pass SSV at * the default threshold (or less restrictive) is sufficient to * pass MSV in essentially all DNA models we've tested. * * Above-threshold diagonals are captured into a preallocated list * <windowlist>. Rather than simply capturing positions at which a * score threshold is reached, this function establishes windows * around those high-scoring positions, using scores in <msvdata>. * These windows can be merged by the calling function. * * * Args: dsq - digital target sequence, 1..L * L - length of dsq in residues * om - optimized profile * ox - DP matrix * msvdata - compact representation of substitution scores, for backtracking diagonals * bg - the background model, required for translating a P-value threshold into a score threshold * P - p-value below which a region is captured as being above threshold * windowlist - preallocated container for all hits (resized if necessary) * * * Note: We misuse the matrix <ox> here, using only a third of the * first dp row, accessing it as <dp[0..Q-1]> rather than * in triplets via <{MDI}MX(q)> macros, since we only need * to store M state values. We know that if <ox> was big * enough for normal DP calculations, it must be big enough * to hold the MSVFilter calculation. * * Returns: <eslOK> on success. * * Throws: <eslEINVAL> if <ox> allocation is too small. */ int p7_SSVFilter_longtarget(const ESL_DSQ *dsq, int L, P7_OPROFILE *om, P7_OMX *ox, const P7_SCOREDATA *msvdata, P7_BG *bg, double P, P7_HMM_WINDOWLIST *windowlist) { register __m128i mpv; /* previous row values */ register __m128i xEv; /* E state: keeps max for Mk->E for a single iteration */ register __m128i xBv; /* B state: splatted vector of B[i-1] for B->Mk calculations */ register __m128i sv; /* temp storage of 1 curr row value in progress */ register __m128i biasv; /* emission bias in a vector */ uint8_t xJ; /* special states' scores */ int i; /* counter over sequence positions 1..L */ int q; /* counter over vectors 0..nq-1 */ int Q = p7O_NQB(om->M); /* segment length: # of vectors */ __m128i *dp = ox->dpb[0]; /* we're going to use dp[0][0..q..Q-1], not {MDI}MX(q) macros*/ __m128i *rsc; /* will point at om->rbv[x] for residue x[i] */ __m128i tecv; /* vector for E->C cost */ __m128i tjbmv; /* vector for J->B move cost + B->M move costs */ __m128i basev; /* offset for scores */ __m128i ceilingv; /* saturated simd value used to test for overflow */ __m128i tempv; /* work vector */ int cmp; int k; int n; int end; int rem_sc; int start; int target_end; int target_start; int max_end; int max_sc; int sc; int pos_since_max; float ret_sc; union { __m128i v; uint8_t b[16]; } u; /* * Computing the score required to let P meet the F1 prob threshold * In original code, converting from a scaled int MSV * score S (the score getting to state E) to a probability goes like this: * usc = S - om->tec_b - om->tjb_b - om->base_b; * usc /= om->scale_b; * usc -= 3.0; * P = f ( (usc - nullsc) / eslCONST_LOG2 , mu, lambda) * and we're computing the threshold usc, so reverse it: * (usc - nullsc) / eslCONST_LOG2 = inv_f( P, mu, lambda) * usc = nullsc + eslCONST_LOG2 * inv_f( P, mu, lambda) * usc += 3 * usc *= om->scale_b * S = usc + om->tec_b + om->tjb_b + om->base_b * * Here, I compute threshold with length model based on max_length. Doesn't * matter much - in any case, both the bg and om models will change with roughly * 1 bit for each doubling of the length model, so they offset. */ float nullsc; __m128i sc_threshv; uint8_t sc_thresh; float invP = esl_gumbel_invsurv(P, om->evparam[p7_MMU], om->evparam[p7_MLAMBDA]); /* Check that the DP matrix is ok for us. */ if (Q > ox->allocQ16) ESL_EXCEPTION(eslEINVAL, "DP matrix allocated too small"); ox->M = om->M; p7_bg_SetLength(bg, om->max_length); p7_oprofile_ReconfigMSVLength(om, om->max_length); p7_bg_NullOne (bg, dsq, om->max_length, &nullsc); sc_thresh = (int) ceil( ( ( nullsc + (invP * eslCONST_LOG2) + 3.0 ) * om->scale_b ) + om->base_b + om->tec_b + om->tjb_b ); sc_threshv = _mm_set1_epi8((int8_t) 255 - sc_thresh); /* Initialization. In offset unsigned arithmetic, -infinity is 0, and 0 is om->base. */ biasv = _mm_set1_epi8((int8_t) om->bias_b); /* yes, you can set1() an unsigned char vector this way */ ceilingv = _mm_cmpeq_epi8(biasv, biasv); for (q = 0; q < Q; q++) dp[q] = _mm_setzero_si128(); xJ = 0; basev = _mm_set1_epi8((int8_t) om->base_b); tecv = _mm_set1_epi8((int8_t) om->tec_b); tjbmv = _mm_set1_epi8((int8_t) om->tjb_b + (int8_t) om->tbm_b); xBv = _mm_subs_epu8(basev, tjbmv); for (i = 1; i <= L; i++) { rsc = om->rbv[dsq[i]]; xEv = _mm_setzero_si128(); /* Right shifts by 1 byte. 4,8,12,x becomes x,4,8,12. * Because ia32 is littlendian, this means a left bit shift. * Zeros shift on automatically, which is our -infinity. */ mpv = _mm_slli_si128(dp[Q-1], 1); for (q = 0; q < Q; q++) { /* Calculate new MMXo(i,q); don't store it yet, hold it in sv. */ sv = _mm_max_epu8(mpv, xBv); sv = _mm_adds_epu8(sv, biasv); sv = _mm_subs_epu8(sv, *rsc); rsc++; xEv = _mm_max_epu8(xEv, sv); mpv = dp[q]; /* Load {MDI}(i-1,q) into mpv */ dp[q] = sv; /* Do delayed store of M(i,q) now that memory is usable */ } /* test if the pthresh significance threshold has been reached; * note: don't use _mm_cmpgt_epi8, because it's a signed comparison, which won't work on uint8s */ tempv = _mm_adds_epu8(xEv, sc_threshv); tempv = _mm_cmpeq_epi8(tempv, ceilingv); cmp = _mm_movemask_epi8(tempv); if (cmp != 0) { //hit pthresh, so add position to list and reset values //figure out which model state hit threshold end = -1; rem_sc = -1; for (q = 0; q < Q; q++) { /// Unpack and unstripe, so we can find the state that exceeded pthresh u.v = dp[q]; for (k = 0; k < 16; k++) { // unstripe //(q+Q*k+1) is the model position k at which the xE score is found if (u.b[k] >= sc_thresh && u.b[k] > rem_sc && (q+Q*k+1) <= om->M) { end = (q+Q*k+1); rem_sc = u.b[k]; } } dp[q] = _mm_set1_epi8(0); // while we're here ... this will cause values to get reset to xB in next dp iteration } //recover the diagonal that hit threshold start = end; target_end = target_start = i; sc = rem_sc; while (rem_sc > om->base_b - om->tjb_b - om->tbm_b) { rem_sc -= om->bias_b - msvdata->msv_scores[start*om->abc->Kp + dsq[target_start]]; --start; --target_start; } start++; target_start++; //extend diagonal further with single diagonal extension k = end+1; n = target_end+1; max_end = target_end; max_sc = sc; pos_since_max = 0; while (k<om->M && n<=L) { sc += om->bias_b - msvdata->msv_scores[k*om->abc->Kp + dsq[n]]; if (sc >= max_sc) { max_sc = sc; max_end = n; pos_since_max=0; } else { pos_since_max++; if (pos_since_max == 5) break; } k++; n++; } end += (max_end - target_end); k += (max_end - target_end); target_end = max_end; ret_sc = ((float) (max_sc - om->tjb_b) - (float) om->base_b); ret_sc /= om->scale_b; ret_sc -= 3.0; // that's ~ L \log \frac{L}{L+3}, for our NN,CC,JJ p7_hmmwindow_new(windowlist, 0, target_start, k, end, end-start+1 , ret_sc, p7_NOCOMPLEMENT ); i = target_end; // skip forward } } /* end loop over sequence residues 1..L */ return eslOK; }
/* Function: p7_MSVFilter() * Synopsis: Calculates MSV score, vewy vewy fast, in limited precision. * Incept: SRE, Wed Dec 26 15:12:25 2007 [Janelia] * * Purpose: Calculates an approximation of the MSV score for sequence * <dsq> of length <L> residues, using optimized profile <om>, * and a preallocated one-row DP matrix <ox>. Return the * estimated MSV score (in nats) in <ret_sc>. * * Score may overflow (and will, on high-scoring * sequences), but will not underflow. * * The model may be in any mode, because only its match * emission scores will be used. The MSV filter inherently * assumes a multihit local mode, and uses its own special * state transition scores, not the scores in the profile. * * Args: dsq - digital target sequence, 1..L * L - length of dsq in residues * om - optimized profile * ox - DP matrix * ret_sc - RETURN: MSV score (in nats) * * Note: We misuse the matrix <ox> here, using only a third of the * first dp row, accessing it as <dp[0..Q-1]> rather than * in triplets via <{MDI}MX(q)> macros, since we only need * to store M state values. We know that if <ox> was big * enough for normal DP calculations, it must be big enough * to hold the MSVFilter calculation. * * Returns: <eslOK> on success. * <eslERANGE> if the score overflows the limited range; in * this case, this is a high-scoring hit. * * Throws: <eslEINVAL> if <ox> allocation is too small. */ int p7_MSVFilter(const ESL_DSQ *dsq, int L, const P7_OPROFILE *om, P7_OMX *ox, float *ret_sc) { register __m128i mpv; /* previous row values */ register __m128i xEv; /* E state: keeps max for Mk->E as we go */ register __m128i xBv; /* B state: splatted vector of B[i-1] for B->Mk calculations */ register __m128i sv; /* temp storage of 1 curr row value in progress */ register __m128i biasv; /* emission bias in a vector */ uint8_t xJ; /* special states' scores */ int i; /* counter over sequence positions 1..L */ int q; /* counter over vectors 0..nq-1 */ int Q = p7O_NQB(om->M); /* segment length: # of vectors */ __m128i *dp = ox->dpb[0]; /* we're going to use dp[0][0..q..Q-1], not {MDI}MX(q) macros*/ __m128i *rsc; /* will point at om->rbv[x] for residue x[i] */ __m128i xJv; /* vector for states score */ __m128i tjbmv; /* vector for cost of moving from either J or N through B to an M state */ __m128i tecv; /* vector for E->C cost */ __m128i basev; /* offset for scores */ __m128i ceilingv; /* saturateed simd value used to test for overflow */ __m128i tempv; /* work vector */ int cmp; int status = eslOK; /* Check that the DP matrix is ok for us. */ if (Q > ox->allocQ16) ESL_EXCEPTION(eslEINVAL, "DP matrix allocated too small"); ox->M = om->M; /* Try highly optimized ssv filter first */ status = p7_SSVFilter(dsq, L, om, ret_sc); if (status != eslENORESULT) return status; /* Initialization. In offset unsigned arithmetic, -infinity is 0, and 0 is om->base. */ biasv = _mm_set1_epi8((int8_t) om->bias_b); /* yes, you can set1() an unsigned char vector this way */ for (q = 0; q < Q; q++) dp[q] = _mm_setzero_si128(); xJ = 0; /* saturate simd register for overflow test */ ceilingv = _mm_cmpeq_epi8(biasv, biasv); basev = _mm_set1_epi8((int8_t) om->base_b); tjbmv = _mm_set1_epi8((int8_t) om->tjb_b + (int8_t) om->tbm_b); tecv = _mm_set1_epi8((int8_t) om->tec_b); xJv = _mm_subs_epu8(biasv, biasv); xBv = _mm_subs_epu8(basev, tjbmv); #if p7_DEBUGGING if (ox->debugging) { uint8_t xB; xB = _mm_extract_epi16(xBv, 0); xJ = _mm_extract_epi16(xJv, 0); p7_omx_DumpMFRow(ox, 0, 0, 0, xJ, xB, xJ); } #endif for (i = 1; i <= L; i++) { rsc = om->rbv[dsq[i]]; xEv = _mm_setzero_si128(); /* Right shifts by 1 byte. 4,8,12,x becomes x,4,8,12. * Because ia32 is littlendian, this means a left bit shift. * Zeros shift on automatically, which is our -infinity. */ mpv = _mm_slli_si128(dp[Q-1], 1); for (q = 0; q < Q; q++) { /* Calculate new MMXo(i,q); don't store it yet, hold it in sv. */ sv = _mm_max_epu8(mpv, xBv); sv = _mm_adds_epu8(sv, biasv); sv = _mm_subs_epu8(sv, *rsc); rsc++; xEv = _mm_max_epu8(xEv, sv); mpv = dp[q]; /* Load {MDI}(i-1,q) into mpv */ dp[q] = sv; /* Do delayed store of M(i,q) now that memory is usable */ } /* test for the overflow condition */ tempv = _mm_adds_epu8(xEv, biasv); tempv = _mm_cmpeq_epi8(tempv, ceilingv); cmp = _mm_movemask_epi8(tempv); /* Now the "special" states, which start from Mk->E (->C, ->J->B) * Use shuffles instead of shifts so when the last max has completed, * the last four elements of the simd register will contain the * max value. Then the last shuffle will broadcast the max value * to all simd elements. */ tempv = _mm_shuffle_epi32(xEv, _MM_SHUFFLE(2, 3, 0, 1)); xEv = _mm_max_epu8(xEv, tempv); tempv = _mm_shuffle_epi32(xEv, _MM_SHUFFLE(0, 1, 2, 3)); xEv = _mm_max_epu8(xEv, tempv); tempv = _mm_shufflelo_epi16(xEv, _MM_SHUFFLE(2, 3, 0, 1)); xEv = _mm_max_epu8(xEv, tempv); tempv = _mm_srli_si128(xEv, 1); xEv = _mm_max_epu8(xEv, tempv); xEv = _mm_shuffle_epi32(xEv, _MM_SHUFFLE(0, 0, 0, 0)); /* immediately detect overflow */ if (cmp != 0x0000) { *ret_sc = eslINFINITY; return eslERANGE; } xEv = _mm_subs_epu8(xEv, tecv); xJv = _mm_max_epu8(xJv,xEv); xBv = _mm_max_epu8(basev, xJv); xBv = _mm_subs_epu8(xBv, tjbmv); #if p7_DEBUGGING if (ox->debugging) { uint8_t xB, xE; xB = _mm_extract_epi16(xBv, 0); xE = _mm_extract_epi16(xEv, 0); xJ = _mm_extract_epi16(xJv, 0); p7_omx_DumpMFRow(ox, i, xE, 0, xJ, xB, xJ); } #endif } /* end loop over sequence residues 1..L */ xJ = (uint8_t) _mm_extract_epi16(xJv, 0); /* finally C->T, and add our missing precision on the NN,CC,JJ back */ *ret_sc = ((float) (xJ - om->tjb_b) - (float) om->base_b); *ret_sc /= om->scale_b; *ret_sc -= 3.0; /* that's ~ L \log \frac{L}{L+3}, for our NN,CC,JJ */ return eslOK; }
/* Function: p7_oprofile_Write() * Synopsis: Write an optimized profile in two files. * Incept: SRE, Wed Jan 21 10:35:28 2009 [Janelia] * * Purpose: Write the MSV filter part of <om> to open binary stream * <ffp>, and the rest of the model to <pfp>. These two * streams will typically be <.h3f> and <.h3p> files * being created by hmmpress. * * Args: ffp - open binary stream for saving MSV filter part * pfp - open binary stream for saving rest of profile * om - optimized profile to save * * Returns: <eslOK> on success. * * Returns <eslFAIL> on any write failure; for example, * if disk is full. * * Throws: (no abnormal error conditions) */ int p7_oprofile_Write(FILE *ffp, FILE *pfp, P7_OPROFILE *om) { int Q4 = p7O_NQF(om->M); int Q8 = p7O_NQW(om->M); int Q16 = p7O_NQB(om->M); int n = strlen(om->name); int x; /* <ffp> is the part of the oprofile that MSVFilter() needs */ if (fwrite((char *) &(v3b_fmagic), sizeof(uint32_t), 1, ffp) != 1) return eslFAIL; if (fwrite((char *) &(om->M), sizeof(int), 1, ffp) != 1) return eslFAIL; if (fwrite((char *) &(om->abc->type), sizeof(int), 1, ffp) != 1) return eslFAIL; if (fwrite((char *) &n, sizeof(int), 1, ffp) != 1) return eslFAIL; if (fwrite((char *) om->name, sizeof(char), n+1, ffp) != n+1) return eslFAIL; if (fwrite((char *) &(om->tbm_b), sizeof(uint8_t), 1, ffp) != 1) return eslFAIL; if (fwrite((char *) &(om->tec_b), sizeof(uint8_t), 1, ffp) != 1) return eslFAIL; if (fwrite((char *) &(om->tjb_b), sizeof(uint8_t), 1, ffp) != 1) return eslFAIL; if (fwrite((char *) &(om->scale_b), sizeof(float), 1, ffp) != 1) return eslFAIL; if (fwrite((char *) &(om->base_b), sizeof(uint8_t), 1, ffp) != 1) return eslFAIL; if (fwrite((char *) &(om->bias_b), sizeof(uint8_t), 1, ffp) != 1) return eslFAIL; for (x = 0; x < om->abc->Kp; x++) if (fwrite( (char *) om->rbv[x], sizeof(vector unsigned char), Q16, ffp) != Q16) return eslFAIL; if (fwrite((char *) om->evparam, sizeof(float), p7_NEVPARAM, ffp) != p7_NEVPARAM) return eslFAIL; if (fwrite((char *) om->offs, sizeof(off_t), p7_NOFFSETS, ffp) != p7_NOFFSETS) return eslFAIL; if (fwrite((char *) om->compo, sizeof(float), p7_MAXABET, ffp) != p7_MAXABET) return eslFAIL; /* <pfp> gets the rest of the oprofile */ if (fwrite((char *) &(v3b_pmagic), sizeof(uint32_t), 1, pfp) != 1) return eslFAIL; if (fwrite((char *) &(om->M), sizeof(int), 1, pfp) != 1) return eslFAIL; if (fwrite((char *) &(om->abc->type), sizeof(int), 1, pfp) != 1) return eslFAIL; if (fwrite((char *) &n, sizeof(int), 1, pfp) != 1) return eslFAIL; if (fwrite((char *) om->name, sizeof(char), n+1, pfp) != n+1) return eslFAIL; if (om->acc == NULL) { n = 0; if (fwrite((char *) &n, sizeof(int), 1, pfp) != 1) return eslFAIL; } else { n = strlen(om->acc); if (fwrite((char *) &n, sizeof(int), 1, pfp) != 1) return eslFAIL; if (fwrite((char *) om->acc, sizeof(char), n+1, pfp) != n+1) return eslFAIL; } if (om->desc == NULL) { n = 0; if (fwrite((char *) &n, sizeof(int), 1, pfp) != 1) return eslFAIL; } else { n = strlen(om->desc); if (fwrite((char *) &n, sizeof(int), 1, pfp) != 1) return eslFAIL; if (fwrite((char *) om->desc, sizeof(char), n+1, pfp) != n+1) return eslFAIL; } if (fwrite((char *) om->rf, sizeof(char), om->M+2, pfp) != om->M+2) return eslFAIL; if (fwrite((char *) om->cs, sizeof(char), om->M+2, pfp) != om->M+2) return eslFAIL; if (fwrite((char *) om->consensus, sizeof(char), om->M+2, pfp) != om->M+2) return eslFAIL; /* ViterbiFilter part */ if (fwrite((char *) om->twv, sizeof(vector signed short), 8*Q8, pfp) != 8*Q8) return eslFAIL; for (x = 0; x < om->abc->Kp; x++) if (fwrite( (char *) om->rwv[x], sizeof(vector signed short), Q8, pfp) != Q8) return eslFAIL; for (x = 0; x < p7O_NXSTATES; x++) if (fwrite( (char *) om->xw[x], sizeof(int16_t), p7O_NXTRANS, pfp) != p7O_NXTRANS) return eslFAIL; if (fwrite((char *) &(om->scale_w), sizeof(float), 1, pfp) != 1) return eslFAIL; if (fwrite((char *) &(om->base_w), sizeof(int16_t), 1, pfp) != 1) return eslFAIL; if (fwrite((char *) &(om->ddbound_w), sizeof(int16_t), 1, pfp) != 1) return eslFAIL; if (fwrite((char *) &(om->ncj_roundoff), sizeof(float), 1, pfp) != 1) return eslFAIL; /* Forward/Backward part */ if (fwrite((char *) om->tfv, sizeof(vector float), 8*Q4, pfp) != 8*Q4) return eslFAIL; for (x = 0; x < om->abc->Kp; x++) if (fwrite( (char *) om->rfv[x], sizeof(vector float), Q4, pfp) != Q4) return eslFAIL; for (x = 0; x < p7O_NXSTATES; x++) if (fwrite( (char *) om->xf[x], sizeof(float), p7O_NXTRANS, pfp) != p7O_NXTRANS) return eslFAIL; if (fwrite((char *) om->cutoff, sizeof(float), p7_NCUTOFFS, pfp) != p7_NCUTOFFS) return eslFAIL; if (fwrite((char *) &(om->nj), sizeof(float), 1, pfp) != 1) return eslFAIL; if (fwrite((char *) &(om->mode), sizeof(int), 1, pfp) != 1) return eslFAIL; if (fwrite((char *) &(om->L) , sizeof(int), 1, pfp) != 1) return eslFAIL; return eslOK; }
/* Function: p7_oprofile_ReadMSVInfo() * Synopsis: Read MSV filter info, but not the scores. * Incept: MSF, Thu Oct 15, 2009 [Janelia] * * Purpose: Read just enough of the MSV filter header from the * <.h3f> file associated with an open HMM file <hfp> * to skip ahead to the next MSV filter. Allocate a new * model, populate it with just the file offsets of this * model and return a pointer to it in <*ret_om>. * * The <.h3f> file was opened automatically, if it existed, * when the HMM file was opened with <p7_hmmfile_Open()>. * * When no more HMMs remain in the file, return <eslEOF>. * * Args: hfp - open HMM file, with associated .h3p file * byp_abc - BYPASS: <*byp_abc == ESL_ALPHABET *> if known; * <*byp_abc == NULL> if desired; * <NULL> if unwanted. * ret_om - RETURN: newly allocated <om> with partial MSV * filter data filled in. * * Returns: <eslOK> on success. <*ret_om> is allocated here; * caller free's with <p7_oprofile_Destroy()>. * <*byp_abc> is allocated here if it was requested; * caller free's with <esl_alphabet_Destroy()>. * * Returns <eslEFORMAT> if <hfp> has no <.h3f> file open, * or on any parsing error. * * Returns <eslEINCOMPAT> if the HMM we read is incompatible * with the existing alphabet <*byp_abc> led us to expect. * * On any returned error, <hfp->errbuf> contains an * informative error message. * * Throws: <eslEMEM> on allocation error. */ int p7_oprofile_ReadInfoMSV(P7_HMMFILE *hfp, ESL_ALPHABET **byp_abc, P7_OPROFILE **ret_om) { P7_OPROFILE *om = NULL; ESL_ALPHABET *abc = NULL; uint32_t magic; off_t roff; int M, Q16; int n; int alphatype; int status; if (hfp->errbuf != NULL) hfp->errbuf[0] = '\0'; if (hfp->ffp == NULL) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "no MSV profile file; hmmpress probably wasn't run"); if (feof(hfp->ffp)) { status = eslEOF; goto ERROR; } /* normal EOF: no more profiles */ /* keep track of the starting offset of the MSV model */ roff = ftello(hfp->ffp); if (! fread( (char *) &magic, sizeof(uint32_t), 1, hfp->ffp)) { status = eslEOF; goto ERROR; } if (magic == v3a_fmagic) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "this is an outdated HMM database (3/a format); please hmmpress your HMM file again"); if (magic != v3b_fmagic) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "bad magic; not an HMM database?"); if (! fread( (char *) &M, sizeof(int), 1, hfp->ffp)) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "failed to read model size M"); if (! fread( (char *) &alphatype, sizeof(int), 1, hfp->ffp)) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "failed to read alphabet type"); Q16 = p7O_NQB(M); /* Set or verify alphabet. */ if (byp_abc == NULL || *byp_abc == NULL) { /* alphabet unknown: whether wanted or unwanted, make a new one */ if ((abc = esl_alphabet_Create(alphatype)) == NULL) ESL_XFAIL(eslEMEM, hfp->errbuf, "allocation failed: alphabet"); } else { /* alphabet already known: verify it against what we see in the HMM */ abc = *byp_abc; if (abc->type != alphatype) ESL_XFAIL(eslEINCOMPAT, hfp->errbuf, "Alphabet type mismatch: was %s, but current profile says %s", esl_abc_DecodeType(abc->type), esl_abc_DecodeType(alphatype)); } /* Now we know the sizes of things, so we can allocate. */ if ((om = p7_oprofile_Create(M, abc)) == NULL) ESL_XFAIL(eslEMEM, hfp->errbuf, "allocation failed: oprofile"); om->M = M; om->roff = roff; /* calculate the remaining length of the msv model */ om->name = NULL; if (!fread((char *) &n, sizeof(int), 1, hfp->ffp)) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "failed to read name length"); roff += (sizeof(int) * 3); /* magic, model size, and alphabet type */ roff += sizeof(int) + n + 1; /* length, name string and terminator '\0' */ roff += (sizeof(float) + sizeof(uint8_t) * 5); /* transition costs, bias, scale and base */ roff += (sizeof(vector signed char) * abc->Kp * Q16); /* msv scores */ roff += (sizeof(float) * p7_NEVPARAM); /* stat params */ roff += (sizeof(off_t) * p7_NOFFSETS); /* hmmpfam offsets */ roff += (sizeof(float) * p7_MAXABET); /* model composition */ /* keep track of the ending offset of the MSV model */ p7_oprofile_Position(hfp, roff); om->eoff = ftello(hfp->ffp) - 1; if (byp_abc != NULL) *byp_abc = abc; /* pass alphabet (whether new or not) back to caller, if caller wanted it */ *ret_om = om; return eslOK; ERROR: if (abc != NULL && (byp_abc == NULL || *byp_abc == NULL)) esl_alphabet_Destroy(abc); /* destroy alphabet if we created it here */ if (om != NULL) p7_oprofile_Destroy(om); *ret_om = NULL; return status; }
/* Function: p7_oprofile_ReadMSV() * Synopsis: Read MSV filter part of an optimized profile. * Incept: SRE, Wed Jan 21 10:39:20 2009 [Janelia] * * Purpose: Read the MSV filter part of a profile from the * <.h3f> file associated with an open HMM file <hfp>. * Allocate a new model, populate it with this minimal * MSV filter information, and return a pointer to it * in <*ret_om>. * * Our alphabet may get set by the first HMM we read. If * <*byp_abc> is <NULL> at start, create a new alphabet and * return a pointer to it in <*byp_abc>. If <*byp_abc> is * non-<NULL>, it is assumed to be a pointer to an existing * alphabet; we verify that the HMM's alphabet matches it * and <*ret_abc> isn't changed. This is the same * convention used by <p7_hmmfile_Read()>. * * The <.h3f> file was opened automatically, if it existed, * when the HMM file was opened with <p7_hmmfile_Open()>. * * When no more HMMs remain in the file, return <eslEOF>. * * Args: hfp - open HMM file, with associated .h3p file * byp_abc - BYPASS: <*byp_abc == ESL_ALPHABET *> if known; * <*byp_abc == NULL> if desired; * <NULL> if unwanted. * ret_om - RETURN: newly allocated <om> with MSV filter * data filled in. * * Returns: <eslOK> on success. <*ret_om> is allocated here; * caller free's with <p7_oprofile_Destroy()>. * <*byp_abc> is allocated here if it was requested; * caller free's with <esl_alphabet_Destroy()>. * * Returns <eslEFORMAT> if <hfp> has no <.h3f> file open, * or on any parsing error. * * Returns <eslEINCOMPAT> if the HMM we read is incompatible * with the existing alphabet <*byp_abc> led us to expect. * * On any returned error, <hfp->errbuf> contains an * informative error message. * * Throws: <eslEMEM> on allocation error. */ int p7_oprofile_ReadMSV(P7_HMMFILE *hfp, ESL_ALPHABET **byp_abc, P7_OPROFILE **ret_om) { P7_OPROFILE *om = NULL; ESL_ALPHABET *abc = NULL; uint32_t magic; off_t roff; int M, Q16; int x,n; int alphatype; int status; if (hfp->errbuf != NULL) hfp->errbuf[0] = '\0'; if (hfp->ffp == NULL) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "no MSV profile file; hmmpress probably wasn't run"); if (feof(hfp->ffp)) { status = eslEOF; goto ERROR; } /* normal EOF: no more profiles */ /* keep track of the starting offset of the MSV model */ roff = ftello(hfp->ffp); if (! fread( (char *) &magic, sizeof(uint32_t), 1, hfp->ffp)) { status = eslEOF; goto ERROR; } if (magic == v3a_fmagic) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "this is an outdated HMM database (3/a format); please hmmpress your HMM file again"); if (magic != v3b_fmagic) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "bad magic; not an HMM database?"); if (! fread( (char *) &M, sizeof(int), 1, hfp->ffp)) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "failed to read model size M"); if (! fread( (char *) &alphatype, sizeof(int), 1, hfp->ffp)) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "failed to read alphabet type"); Q16 = p7O_NQB(M); /* Set or verify alphabet. */ if (byp_abc == NULL || *byp_abc == NULL) { /* alphabet unknown: whether wanted or unwanted, make a new one */ if ((abc = esl_alphabet_Create(alphatype)) == NULL) ESL_XFAIL(eslEMEM, hfp->errbuf, "allocation failed: alphabet"); } else { /* alphabet already known: verify it against what we see in the HMM */ abc = *byp_abc; if (abc->type != alphatype) ESL_XFAIL(eslEINCOMPAT, hfp->errbuf, "Alphabet type mismatch: was %s, but current profile says %s", esl_abc_DecodeType(abc->type), esl_abc_DecodeType(alphatype)); } /* Now we know the sizes of things, so we can allocate. */ if ((om = p7_oprofile_Create(M, abc)) == NULL) ESL_XFAIL(eslEMEM, hfp->errbuf, "allocation failed: oprofile"); om->M = M; om->roff = roff; if (! fread((char *) &n, sizeof(int), 1, hfp->ffp)) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "failed to read name length"); ESL_ALLOC(om->name, sizeof(char) * (n+1)); if (! fread((char *) om->name, sizeof(char), n+1, hfp->ffp)) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "failed to read name"); if (! fread((char *) &(om->tbm_b), sizeof(uint8_t), 1, hfp->ffp)) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "failed to read tbm"); if (! fread((char *) &(om->tec_b), sizeof(uint8_t), 1, hfp->ffp)) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "failed to read tec"); if (! fread((char *) &(om->tjb_b), sizeof(uint8_t), 1, hfp->ffp)) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "failed to read tjb"); if (! fread((char *) &(om->scale_b),sizeof(float), 1, hfp->ffp)) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "failed to read scale"); if (! fread((char *) &(om->base_b), sizeof(uint8_t), 1, hfp->ffp)) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "failed to read base"); if (! fread((char *) &(om->bias_b), sizeof(uint8_t), 1, hfp->ffp)) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "failed to read bias"); for (x = 0; x < abc->Kp; x++) if (! fread((char *) om->rbv[x], sizeof(vector unsigned char), Q16, hfp->ffp)) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "failed to read msv scores at %d [residue %c]", x, abc->sym[x]); if (! fread((char *) om->evparam, sizeof(float), p7_NEVPARAM, hfp->ffp)) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "failed to read stat params"); if (! fread((char *) om->offs, sizeof(off_t), p7_NOFFSETS, hfp->ffp)) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "failed to read hmmpfam offsets"); if (! fread((char *) om->compo, sizeof(float), p7_MAXABET, hfp->ffp)) ESL_XFAIL(eslEFORMAT, hfp->errbuf, "failed to read model composition"); /* keep track of the ending offset of the MSV model */ om->eoff = ftello(hfp->ffp) - 1;; if (byp_abc != NULL) *byp_abc = abc; /* pass alphabet (whether new or not) back to caller, if caller wanted it */ *ret_om = om; return eslOK; ERROR: if (abc != NULL && (byp_abc == NULL || *byp_abc == NULL)) esl_alphabet_Destroy(abc); /* destroy alphabet if we created it here */ if (om != NULL) p7_oprofile_Destroy(om); *ret_om = NULL; return status; }
/* Function: p7_omx_GrowTo() * Synopsis: Assure that a DP matrix is big enough. * Incept: SRE, Thu Dec 20 09:27:07 2007 [Janelia] * * Purpose: Assures that an optimized DP matrix <ox> is allocated for * a model up to <allocM> in length; if not, reallocate to * make it so. * * Because the optimized matrix is one-row, only the model * length matters; the target sequence length isn't * relevant. * * Returns: <eslOK> on success, and <gx> may be reallocated upon * return; any data that may have been in <gx> must be * assumed to be invalidated. * * Throws: <eslEMEM> on allocation failure, and any data that may * have been in <gx> must be assumed to be invalidated. */ int p7_omx_GrowTo(P7_OMX *ox, int allocM, int allocL, int allocXL) { void *p; int nqf = p7O_NQF(allocM); /* segment length; total # of striped vectors for uchar */ int nqw = p7O_NQW(allocM); /* segment length; total # of striped vectors for float */ int nqb = p7O_NQB(allocM); /* segment length; total # of striped vectors for float */ size_t ncells = (allocL+1) * nqf * 4; int reset_row_pointers = FALSE; int i; int status; /* If all possible dimensions are already satisfied, the matrix is fine */ if (ox->allocQ4*4 >= allocM && ox->validR > allocL && ox->allocXR >= allocXL+1) return eslOK; /* If the main matrix is too small in cells, reallocate it; * and we'll need to realign/reset the row pointers later. */ if (ncells > ox->ncells) { ESL_RALLOC(ox->dp_mem, p, sizeof(__m128) * (allocL+1) * nqf * p7X_NSCELLS + 15); ox->ncells = ncells; reset_row_pointers = TRUE; } /* If the X beams are too small, reallocate them. */ if (allocXL+1 >= ox->allocXR) { ESL_RALLOC(ox->x_mem, p, sizeof(float) * (allocXL+1) * p7X_NXCELLS + 15); ox->allocXR = allocXL+1; ox->xmx = (float *) ( ( (unsigned long int) ((char *) ox->x_mem + 15) & (~0xf))); } /* If there aren't enough rows, reallocate the row pointers; we'll * realign and reset them later. */ if (allocL >= ox->allocR) { ESL_RALLOC(ox->dpb, p, sizeof(__m128i *) * (allocL+1)); ESL_RALLOC(ox->dpw, p, sizeof(__m128i *) * (allocL+1)); ESL_RALLOC(ox->dpf, p, sizeof(__m128 *) * (allocL+1)); ox->allocR = allocL+1; reset_row_pointers = TRUE; } /* must we widen the rows? */ if (allocM > ox->allocQ4*4) reset_row_pointers = TRUE; /* must we set some more valid row pointers? */ if (allocL >= ox->validR) reset_row_pointers = TRUE; /* now reset the row pointers, if needed */ if (reset_row_pointers) { ox->dpb[0] = (__m128i *) ( ( (unsigned long int) ((char *) ox->dp_mem + 15) & (~0xf))); ox->dpw[0] = (__m128i *) ( ( (unsigned long int) ((char *) ox->dp_mem + 15) & (~0xf))); ox->dpf[0] = (__m128 *) ( ( (unsigned long int) ((char *) ox->dp_mem + 15) & (~0xf))); ox->validR = ESL_MIN( ox->ncells / (nqf * 4), ox->allocR); for (i = 1; i < ox->validR; i++) { ox->dpb[i] = ox->dpb[0] + i * nqb; ox->dpw[i] = ox->dpw[0] + i * nqw * p7X_NSCELLS; ox->dpf[i] = ox->dpf[0] + i * nqf * p7X_NSCELLS; } ox->allocQ4 = nqf; ox->allocQ8 = nqw; ox->allocQ16 = nqb; } ox->M = 0; ox->L = 0; return eslOK; ERROR: return status; }
/* Function: p7_MSVFilter() * Synopsis: Calculates MSV score, vewy vewy fast, in limited precision. * Incept: SRE, Wed Dec 26 15:12:25 2007 [Janelia] * * Purpose: Calculates an approximation of the MSV score for sequence * <dsq> of length <L> residues, using optimized profile <om>, * and a preallocated one-row DP matrix <ox>. Return the * estimated MSV score (in nats) in <ret_sc>. * * Score may overflow (and will, on high-scoring * sequences), but will not underflow. * * The model may be in any mode, because only its match * emission scores will be used. The MSV filter inherently * assumes a multihit local mode, and uses its own special * state transition scores, not the scores in the profile. * * Args: dsq - digital target sequence, 1..L * L - length of dsq in residues * om - optimized profile * ox - DP matrix * ret_sc - RETURN: MSV score (in nats) * * Note: We misuse the matrix <ox> here, using only a third of the * first dp row, accessing it as <dp[0..Q-1]> rather than * in triplets via <{MDI}MX(q)> macros, since we only need * to store M state values. We know that if <ox> was big * enough for normal DP calculations, it must be big enough * to hold the MSVFilter calculation. * * Returns: <eslOK> on success. * <eslERANGE> if the score overflows the limited range; in * this case, this is a high-scoring hit. * * Throws: <eslEINVAL> if <ox> allocation is too small. */ int p7_MSVFilter(const ESL_DSQ *dsq, int L, const P7_OPROFILE *om, P7_OMX *ox, float *ret_sc) { vector unsigned char mpv; /* previous row values */ vector unsigned char xEv; /* E state: keeps max for Mk->E as we go */ vector unsigned char xBv; /* B state: splatted vector of B[i-1] for B->Mk calculations */ vector unsigned char sv; /* temp storage of 1 curr row value in progress */ vector unsigned char biasv; /* emission bias in a vector */ uint8_t xJ; /* special states' scores */ int i; /* counter over sequence positions 1..L */ int q; /* counter over vectors 0..nq-1 */ int Q = p7O_NQB(om->M); /* segment length: # of vectors */ vector unsigned char *dp; /* we're going to use dp[0][0..q..Q-1], not {MDI}MX(q) macros*/ vector unsigned char *rsc; /* will point at om->rbv[x] for residue x[i] */ vector unsigned char zerov; /* vector of zeros */ vector unsigned char xJv; /* vector for states score */ vector unsigned char tjbmv; /* vector for B->Mk cost */ vector unsigned char tecv; /* vector for E->C cost */ vector unsigned char basev; /* offset for scores */ vector unsigned char ceilingv; /* saturateed simd value used to test for overflow */ vector unsigned char tempv; /* Check that the DP matrix is ok for us. */ if (Q > ox->allocQ16) ESL_EXCEPTION(eslEINVAL, "DP matrix allocated too small"); ox->M = om->M; /* Initialization. In offset unsigned arithmetic, -infinity is 0, and 0 is om->base. */ dp = ox->dpb[0]; for (q = 0; q < Q; q++) dp[q] = vec_splat_u8(0); xJ = 0; biasv = esl_vmx_set_u8(om->bias_b); zerov = vec_splat_u8(0); /* saturate simd register for overflow test */ tempv = vec_splat_u8(1); ceilingv = (vector unsigned char)vec_cmpeq(biasv, biasv); ceilingv = vec_subs(ceilingv, biasv); ceilingv = vec_subs(ceilingv, tempv); basev = esl_vmx_set_u8((int8_t) om->base_b); tecv = esl_vmx_set_u8((int8_t) om->tec_b); tjbmv = esl_vmx_set_u8((int8_t) om->tjb_b + (int8_t) om->tbm_b); xJv = vec_subs(biasv, biasv); xBv = vec_subs(basev, tjbmv); #if p7_DEBUGGING if (ox->debugging) { unsigned char xB; vec_ste(xBv, 0, &xB); vec_ste(xJv, 0, &xJ); p7_omx_DumpMFRow(ox, 0, 0, 0, xJ, xB, xJ); } #endif for (i = 1; i <= L; i++) { rsc = om->rbv[dsq[i]]; xEv = vec_splat_u8(0); // xBv = vec_sub(xBv, tbmv); /* Right shifts by 1 byte. 4,8,12,x becomes x,4,8,12. * Because ia32 is littlendian, this means a left bit shift. * Zeros shift on automatically, which is our -infinity. */ mpv = vec_sld(zerov, dp[Q-1], 15); for (q = 0; q < Q; q++) { /* Calculate new MMXo(i,q); don't store it yet, hold it in sv. */ sv = vec_max(mpv, xBv); sv = vec_adds(sv, biasv); sv = vec_subs(sv, *rsc); rsc++; xEv = vec_max(xEv, sv); mpv = dp[q]; /* Load {MDI}(i-1,q) into mpv */ dp[q] = sv; /* Do delayed store of M(i,q) now that memory is usable */ } /* Now the "special" states, which start from Mk->E (->C, ->J->B) * Use rotates instead of shifts so when the last max has completed, * all elements of the simd register will contain the max value. */ tempv = vec_sld(xEv, xEv, 1); xEv = vec_max(xEv, tempv); tempv = vec_sld(xEv, xEv, 2); xEv = vec_max(xEv, tempv); tempv = vec_sld(xEv, xEv, 4); xEv = vec_max(xEv, tempv); tempv = vec_sld(xEv, xEv, 8); xEv = vec_max(xEv, tempv); /* immediately detect overflow */ if (vec_any_gt(xEv, ceilingv)) { *ret_sc = eslINFINITY; return eslERANGE; } xEv = vec_subs(xEv, tecv); xJv = vec_max(xJv,xEv); xBv = vec_max(basev, xJv); xBv = vec_subs(xBv, tjbmv); #if p7_DEBUGGING if (ox->debugging) { unsigned char xB, xE; vec_ste(xBv, 0, &xB); vec_ste(xEv, 0, &xE); vec_ste(xJv, 0, &xJ); p7_omx_DumpMFRow(ox, i, xE, 0, xJ, xB, xJ); } #endif } /* end loop over sequence residues 1..L */ /* finally C->T, and add our missing precision on the NN,CC,JJ back */ vec_ste(xJv, 0, &xJ); *ret_sc = ((float) (xJ - om->tjb_b) - (float) om->base_b); *ret_sc /= om->scale_b; *ret_sc -= 3.0; /* that's ~ L \log \frac{L}{L+3}, for our NN,CC,JJ */ return eslOK; }