// Map routines to iterate a function over an array, potentially splitting the array slice into // chunks so that each chunk is processed concurrently. When using concurrent processing the // Chunk size is either the nearest even division of the total array over the chosen concurrent // processing goroutines or a specified maximum chunk size, whichever is smaller. Reducing // chunk size can reduce the impact of divergence in time for processing chunks, but may add // to overhead. func Map(set Mapper, threads, maxChunkSize int) (results []interface{}, err error) { queue := make(chan Operator, 1) p := NewProcessor(queue, 0, threads) defer p.Stop() chunkSize := util.Min(int(math.Ceil(float64(set.Len())/float64(threads))), maxChunkSize) quit := make(chan struct{}) go func() { for s := 0; s*chunkSize < set.Len(); s++ { select { case <-quit: break default: endChunk := util.Min(chunkSize*(s+1), set.Len()) queue <- set.Slice(chunkSize*s, endChunk) } } }() for r := 0; r*chunkSize < set.Len(); r++ { result := <-p.out if result.Err != nil { err = bio.NewError("Map failed", 0, err) close(quit) break } results = append(results, result.Value) } return }
// Render the rainbow based on block of sequence in the index with the given size. Left and right define the extent of the rendering. // Vary specifies which color values change in response to kmer frequency. func (self *KmerRainbow) Paint(vary int, block, size, left, right int) (i *image.RGBA, err error) { right = util.Min(right, self.Rect.Dx()) kmers := make([]uint32, self.RGBA.Rect.Dy()) kmask := util.Pow4(self.Index.GetK()) kmaskf := float64(kmask) f := func(index *kmerindex.Index, _, kmer int) { kmers[int(float64(kmer)*float64(self.RGBA.Rect.Dy())/kmaskf)]++ } self.Index.ForEachKmerOf(self.Index.Seq, block*size, (block+1)*size-1, f) c := color.HSVA{} lf := float64(len(kmers)) / 360 var val float64 scale := 1 / float64(self.Max) for y, v := range kmers { val = float64(v) / scale c.H = float64(y) / lf if vary&S != 0 { c.S = val } else { c.S = self.BackGround.S } if vary&V != 0 { c.V = val } else { c.V = self.BackGround.V } if vary&A != 0 { c.A = val } else { c.A = self.BackGround.A } if left >= 0 && right > left { for x := left; x < right; x++ { self.Set(x, y, c) } } else { println(left, right) for x := 0; x < self.Rect.Dx(); x++ { self.Set(x, y, c) } } } return self.RGBA, nil }
func processServer(index interval.Tree, queue, output chan *feat.Feature, wg *sync.WaitGroup) { defer wg.Done() var ( buffer []byte = make([]byte, 0, annotationLength) annotations Matches = make(Matches, 0, maxAnnotations+1) o *Overlap = &Overlap{&annotations} prefix string = ` ; Annot "` blank string = prefix + strings.Repeat("-", mapLength) overlap int ) for feature := range queue { annotations = annotations[:0] heap.Init(&Overlap{&annotations}) buffer = buffer[:0] buffer = append(buffer, []byte(blank)...) if query, err := interval.New(string(feature.Location), feature.Start, feature.End, 0, nil); err != nil { fmt.Fprintf(os.Stderr, "Feature has end < start: %v\n", feature) continue } else { overlap = int(float64(feature.Len()) * minOverlap) if results := index.Intersect(query, overlap); results != nil { for hit := range results { o.Push(Match{ Interval: hit, Overlap: util.Min(hit.End(), query.End()) - util.Max(hit.Start(), query.Start()), Strand: feature.Strand, }) if len(annotations) > maxAnnotations { o.Pop() } } } } if len(annotations) > 0 { sort.Sort(&Start{&annotations}) buffer = makeAnnotation(feature, annotations, len(prefix), buffer) } buffer = append(buffer, '"') feature.Attributes += string(buffer) output <- feature } }
func makeAnnotation(feature *feat.Feature, annotations Matches, prefixLen int, buffer []byte) []byte { var ( annot []byte = buffer[prefixLen:] repRecord RepeatRecord repLocation *interval.Interval start, end, length int repStart, repEnd, repLeft, repLength int leftMargin, rightMargin float64 leftEnd, rightEnd bool mapStart, mapEnd int fullRepLength, repMissing int i int cLower, cUpper byte p string ) length = feature.Len() for annotIndex, repeat := range annotations { repRecord = repeat.Interval.Meta.(RepeatRecord) repLocation = repeat.Interval start = util.Max(repLocation.Start(), feature.Start) end = util.Min(repLocation.End(), feature.End) if repStart = repRecord.Start; repStart != -1 { repEnd = repRecord.End repLeft = repRecord.Left repLength = repStart + repLeft - 1 if repLength <= 0 { repLength = 9999 } if repLocation.Start() < feature.Start { repStart += feature.Start - repLocation.Start() } if repLocation.End() > feature.End { repEnd -= repLocation.End() - feature.End } leftMargin = float64(repStart) / float64(repLength) rightMargin = float64(repLeft) / float64(repLength) leftEnd = (leftMargin <= maxMargin) rightEnd = (rightMargin <= maxMargin) } mapStart = ((start - feature.Start) * mapLength) / length mapEnd = ((end - feature.Start) * mapLength) / length if feature.Strand == -1 { mapStart, mapEnd = mapLength-mapEnd-1, mapLength-mapStart-1 } if mapStart < 0 || mapStart >= mapLength || mapEnd < 0 || mapEnd >= mapLength { fmt.Printf("mapStart: %d, mapEnd: %d, mapLength: %d\n", mapStart, mapEnd, mapLength) panic("MakeAnnot: failed to map") } cLower = 'a' + byte(annotIndex) cUpper = 'A' + byte(annotIndex) if leftEnd { annot[mapStart] = cUpper } else { annot[mapStart] = cLower } for i = mapStart + 1; i <= mapEnd-1; i++ { annot[i] = cLower } if rightEnd { annot[mapEnd] = cUpper } else { annot[mapEnd] = cLower } buffer = append(buffer, ' ') buffer = append(buffer, []byte(repRecord.Name)...) if repRecord.Start >= 0 { fullRepLength = repRecord.End + repLeft repMissing = repRecord.Start + repLeft if feature.Start > repLocation.Start() { repMissing += feature.Start - repLocation.Start() } if repLocation.End() > feature.End { repMissing += repLocation.End() - feature.End } p = fmt.Sprintf("(%.0f%%)", ((float64(fullRepLength)-float64(repMissing))*100)/float64(fullRepLength)) buffer = append(buffer, []byte(p)...) } } return buffer }