// on the PC // go run grump-reader.go -tkvdata="C:\Users\peugeot\tkv-data" func main() { // flag "country" countryPtr := flag.String("country", "fra", "iso 3166 country code") targetMaxBodiesPtr := flag.String("targetMaxBodies", "100000", "target nb of bodies") // get the directory containing tkv data through the flag "tkvdata" dirTKVDataPtr := flag.String("tkvdata", "/Users/thomaspeugeot/the-mapping-data/", "directory containing input tkv data") var country grump.Country flag.Parse() { _, errScan := fmt.Sscanf(*targetMaxBodiesPtr, "%d", &targetMaxBodies) if errScan != nil { log.Fatal(errScan) return } } grump.Info.Printf("country to parse %s", *countryPtr) country.Name = *countryPtr grump.Info.Printf("directory containing tkv data %s", *dirTKVDataPtr) dirTKVData := *dirTKVDataPtr // create the path to the agragate country count grumpFilePath := fmt.Sprintf("%s/%s_grumpv1_pcount_00_ascii_30/%sup00ag.asc", dirTKVData, *countryPtr, *countryPtr) grump.Info.Printf("relative path %s", filepath.Clean(grumpFilePath)) var grumpFile *os.File var err error grumpFile, err = os.Open(filepath.Clean(grumpFilePath)) if err != nil { log.Fatal(err) } // parse the grump var word int scanner := bufio.NewScanner(grumpFile) scanner.Split(bufio.ScanWords) // scan 8 first lines scanner.Scan() scanner.Scan() fmt.Sscanf(scanner.Text(), "%d", &country.NCols) scanner.Scan() scanner.Scan() fmt.Sscanf(scanner.Text(), "%d", &country.NRows) scanner.Scan() scanner.Scan() fmt.Sscanf(scanner.Text(), "%d", &country.XllCorner) scanner.Scan() scanner.Scan() fmt.Sscanf(scanner.Text(), "%d", &country.YllCorner) country.Serialize() grump.Info.Println("country struct content is ", country) // scan the reamining header for word < 4 { scanner.Scan() word++ fmt.Println(fmt.Sprintf("item %d : %s", word, scanner.Text())) } colLngWidth := 0.0083333333333 // prepare the count matrix countMatrix := make([]float64, country.NRows*country.NCols) popTotal := 0.0 // scan the file and store result in countMatrix for row := 0; row < country.NRows; row++ { lat := country.Row2Lat(row) for col := 0; col < country.NCols; col++ { scanner.Scan() // lng := float64(country.XllCorner) + (float64(col)*colLngWidth) var count float64 fmt.Sscanf(scanner.Text(), "%f", &count) popTotal += count countMatrix[(country.NRows-row-1)*country.NCols+col] = count } fmt.Printf("\rrow %5d lat %2.3f total %f", row, lat, popTotal) } fmt.Printf("\n") grump.Info.Printf("reading grump file is over, closing") grumpFile.Close() // get the arrangement arrangements := make(arrangementsStore, maxCirclePerCell+1) for nbCircles := 1; nbCircles <= maxCirclePerCell; nbCircles++ { fmt.Printf("\rgetting arrangement for %3d circles", nbCircles) arrangements[nbCircles] = make([]circleCoord, nbCircles) // open the reference file circlePackingFilePath := fmt.Sprintf("%s/csq_coords/csq%d.txt", dirTKVData, nbCircles) var circlePackingFile *os.File var errCirclePackingFile error circlePackingFile, errCirclePackingFile = os.Open(filepath.Clean(circlePackingFilePath)) if errCirclePackingFile != nil { log.Fatal(err) } // prepare scanner scannerCircle := bufio.NewScanner(circlePackingFile) scannerCircle.Split(bufio.ScanWords) // one line per circle for circle := 0; circle < nbCircles; circle++ { // scan the id of the circle scannerCircle.Scan() // scan X coordinate scannerCircle.Scan() fmt.Sscanf(scannerCircle.Text(), "%f", &(arrangements[nbCircles][circle].x)) // scan Y coordinate scannerCircle.Scan() fmt.Sscanf(scannerCircle.Text(), "%f", &(arrangements[nbCircles][circle].y)) // fmt.Printf("getting arrangement for %d circle %3d, coord %f %f\n", nbCircles, circle, arrangements[nbCircles][circle].x, arrangements[nbCircles][circle].y) } circlePackingFile.Close() } grump.Info.Printf("reading circle packing files is over") // prepare the output density file var bodies []quadtree.Body bodiesInCellMax := 0 grump.Info.Printf("Preparing the ouput") cumulativePopTotal := 0.0 bodiesNb := 0 for row := 0; row < country.NRows; row++ { lat := country.Row2Lat(row) for col := 0; col < country.NCols; col++ { lng := float64(country.XllCorner) + (float64(col) * colLngWidth) // compute relative coordinate of the cell relX, relY := country.LatLng2XY(lat, lng) // fetch count of the cell count := countMatrix[row*country.NCols+col] // how many bodies ? it is maxBodies *( count / country.PCount) bodiesInCell := int(math.Floor(float64(targetMaxBodies) * count / popTotal)) massPerBody := float64(count) / float64(bodiesInCell) if bodiesInCell > bodiesInCellMax { bodiesInCellMax = bodiesInCell } if bodiesInCell > maxCirclePerCell { grump.Error.Printf("bodiesInCell %d superior to maxCirclePerCell %d", bodiesInCell, maxCirclePerCell) bodiesInCell = maxCirclePerCell massPerBody = float64(count) / float64(bodiesInCell) } // initiate the bodies for i := 0; i < bodiesInCell; i++ { var body quadtree.Body // angle := float64(i) * 2.0 * math.Pi / float64(bodiesInCell) body.X = relX + (1.0/float64(country.NCols))*(0.5+arrangements[bodiesInCell][i].x) body.Y = relY + (1.0/float64(country.NRows))*(0.5+arrangements[bodiesInCell][i].y) body.M = massPerBody bodies = append(bodies, body) } cumulativePopTotal += count bodiesNb += bodiesInCell } } // var quadtree quadtree.Quadtree // quadtree.Init( &bodies) fmt.Println("bodies in cell max ", bodiesInCellMax) fmt.Println("cumulative pop ", cumulativePopTotal) fmt.Println("nb of bodies ", bodiesNb) var run barnes_hut.Run run.Init(&bodies) run.OutputDir = "." run.SetCountry(country.Name) run.CaptureConfig() }
// compute repulsion field at interpolation point x, y and update v func (f *RepulsionField) ComputeFieldRecursive(x, y float64, q *quadtree.Quadtree, coord quadtree.Coord, v *float64) { Trace.Printf("ComputeFieldRecursive at %e %e, quadtree %p, coord %s, input v = %e\n", x, y, q, coord.String(), *v) var body quadtree.Body body.X = x body.Y = y // compute the node box size level := coord.Level() boxSize := 1.0 / math.Pow(2.0, float64(level)) // if level = 0, this is 1.0 node := &(q.Nodes[coord]) distToNode := getModuloDistanceBetweenBodies(&body, &(node.Body)) // avoid node with zero mass if node.M == 0 { return } // check if the COM of the node can be used if (boxSize / distToNode) < BN_THETA { *v += getRepulsionField(&body, &(node.Body)) } else { if level < 8 { // parse sub nodes Trace.Printf("ComputeFieldRecursive go down at node %#v\n", node.Coord()) coordNW, coordNE, coordSW, coordSE := quadtree.NodesBelow(coord) f.ComputeFieldRecursive(x, y, q, coordNW, v) f.ComputeFieldRecursive(x, y, q, coordNE, v) f.ComputeFieldRecursive(x, y, q, coordSW, v) f.ComputeFieldRecursive(x, y, q, coordSE, v) } else { // parse bodies of the node rank := 0 rankOfBody := -1 for b := node.First(); b != nil; b = b.Next() { if *b != body { dist := getModuloDistanceBetweenBodies(&body, b) if dist == 0.0 { var t testing.T q.CheckIntegrity(&t) // c1 := body.Coord() // c2 := b.Coord() Error.Printf("Problem at rank %d for body of rank %d on node %#v ", rank, rankOfBody, *node) } // if distance is inferior to cutoff, return if dist < f.cutoff { *v = 0.0 return } else { *v += getRepulsionField(&body, b) } rank++ Trace.Printf("ComputeFieldRecursive at leaf %#v rank %d x %9.3f y %9.3f\n", b.Coord(), rank, x, y) } else { rankOfBody = rank } } } } return }