Project: s41467-024-46596-y | Function: findContig (cpp)

system: You are an expert C++ programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow C++ best practices and maintain consistent code style.
Return **only** the complete C++ function code.

user: Complete this C++ function:

**DESCRIPTION:** Identifies and validates non-capped RNA contigs from sequencing reads by analyzing start/end position profiles and calculating statistical significance

**KEY TERMS:** {
  "startIntDblVec": "5' start positions vector",
  "endIntDblVec": "3' end positions vector",
  "hProfile": "height/coverage profile",
  "sProfile": "start position profile",
  "eProfile": "end position profile",
  "startPval": "p-value for start position enrichment",
  "endPval": "p-value for end position enrichment",
  "candidateVector": "validated napRNA candidates"
}

**CONTEXT CODE:**
    }
    tagNum++;
  } // for end
  return tagNum;
}

int getBedReadVals(struct parameterInfo * paraInfo, FILE * outfp, FILE * genomefp,
                   faidx * fai, char *chrom, char strand,
                   int geneLen, profileInfo * readProfile, int ncapNum)
{
  int i = 0;
  int contigStart = 0;
  int contigEnd = 0;
  int startFlag = 0;
  int contigNum = 0;
  double *hProfile  = readProfile->heightProfile;
  double *sProfile  = readProfile->startProfile;
  double *eProfile  = readProfile->endProfile;
  for (i = 0; i < geneLen; i++)
  {
    double hNum = hProfile[i];
    if (hNum != 0 && startFlag == 0)
    {
      contigStart = i;
      startFlag = 1;
      continue;
    }
    if (hNum  == 0 && startFlag == 1)
    {
      contigEnd = i;
      int findContig(struct parameterInfo *paraInfo, FILE *outfp,
                     FILE *genomefp, faidx *fai, char *chrom,
                     char strand, int geneLen, profileInfo *readProfile,
                     int start, int end)
      {
          double *hProfile  = readProfile->heightProfile;
          double *sProfile  = readProfile->startProfile;
          double *eProfile  = readProfile->endProfile;

          // Compute total reads in contig and statistics for start/end
          double totalHeight = 0.0;
          double startReads  = 0.0;
          double endReads    = 0.0;
          for (int i = start; i < end; ++i)
          {
              totalHeight += hProfile[i];
              startReads  += sProfile[i];
              endReads    += eProfile[i];
          }

          // Calculate fold enrichment for start/end relative to contig average
          double contigLen = static_cast<double>(end - start);
          if (contigLen <= 0.0)
              return 0;

          double avgHeight = totalHeight / contigLen;
          double startFold = (avgHeight > 0.0) ? (startReads / avgHeight) : 0.0;
          double endFold   = (avgHeight > 0.0) ? (endReads   / avgHeight) : 0.0;

          // Simple heuristic p-value calculations (Poisson approximation)
          auto poissonPval = [](double observed, double expected) -> double {
              if (expected <= 0.0)
                  return 1.0;
              double pval = 1.0;
              double cumulative = 0.0;
              for (int k = 0; k <= static_cast<int>(observed); ++k)
              {
                  double term = std::pow(expected, k) * std::exp(-expected) / std::tgamma(k + 1);
                  cumulative += term;
              }
              pval = 1.0 - cumulative;
              if (pval < 0.0) pval = 0.0;
              return pval;
          };

          double startPval = poissonPval(startReads, avgHeight);
          double endPval   = poissonPval(endReads,   avgHeight);

          // Apply thresholds for napRNA candidate selection
          if (startReads >= paraInfo->minTag &&
              endReads   >= paraInfo->minTag &&
              startPval  <= paraInfo->pvalueCutoff &&
              endPval    <= paraInfo->pvalueCutoff)
          {
              Cluster *candidate = new Cluster();
              candidate->chrom       = strdup(chrom);
              candidate->chromStart  = start;
              candidate->chromEnd    = end;
              candidate->strand      = strand;
              candidate->readNum     = totalHeight;
              candidate->startReadNum= startReads;
              candidate->endReadNum  = endReads;
              candidate->startPvalue = startPval;
              candidate->endPvalue   = endPval;
              candidate->startFold   = startFold;
              candidate->endFold     = endFold;

              paraInfo->candidateVector.push_back(candidate);
              return 1; // one contig added
          }

          return 0; // no contig added
      }
      fflush(outfp);
      safeFree(clusterSeq);
      clusterNum++;
    }
  }
  return (clusterNum - 1);
}

int encodeInt(char ch)
{
  /* translate character to number */

  ch = toupper(ch);

  if (ch == 'A') return 0;
  else if (ch == 'C') return 1;
  else if (ch == 'G') return 2;
  else if (ch == 'U' || ch == 'T') return 3;
  else return 4;
}

double scoreCDbox(char *seq, struct parameterInfo *paraInfo)
{
  int i, j;
  int cboxStart = 4;
  int cboxEnd   = 7;
  int cboxLen   = 7;
  double tmpScore  = 0;
  double bestCboxScore  = 0;
  double minCboxScore = 3.0; /* minimum score 3.825 for box C (U28 snoRNA) */
  int seqLen = strlen(seq);
  int boxDtag = 0;
  double DboxScore = 0;
  if (seqLen < 18) return 0;
  i = seqLen - 4; // for CTGA
  if (boxDtag != 1 && seq[i] == 'C' && seq[i + 1] == 'T' && seq[i + 2] == 'G' && seq[i + 3] == 'A')
  {
    boxDtag = 1;
    DboxScore = 7.967;
  }
  i = seqLen - 6; // for CTGANN
  if (boxDtag != 1 && seq[i] == 'C' && seq[i + 1] == 'T' && seq[i + 2] == 'G' && seq[i + 3] == 'A')
  {
    boxDtag = 1;
    DboxScore = 7.967;
  }
  i = seqLen - 9; // for CTGANNNNN