func WriteAsciiBTL2(nc *lib.Nc, map_format map[string]string, hdr []string, inst string) { // define 2 files, profiles header and data var asciiFilename string // build filenames str := nc.Attributes["cycle_mesure"] str = strings.Replace(str, "\r", "", -1) headerFilename := fmt.Sprintf("output/%s."+inst, strings.ToLower(str)) asciiFilename = fmt.Sprintf("output/%s%s_"+inst, strings.ToLower(str), prefixAll) //fmt.Println(headerFilename) //fmt.Println(asciiFilename) // open header file for writing result fid_hdr, err := os.Create(headerFilename) if err != nil { log.Fatal(err) } defer fid_hdr.Close() // use buffered mode for writing fbuf_hdr := bufio.NewWriter(fid_hdr) // open ASCII file for writing result fid_ascii, err := os.Create(asciiFilename) if err != nil { log.Fatal(err) } defer fid_ascii.Close() // use buffered mode for writing fbuf_ascii := bufio.NewWriter(fid_ascii) // write header to string str = fmt.Sprintf("%s %s %s %s %s %s\n", nc.Attributes["cycle_mesure"], nc.Attributes["plateforme"], nc.Attributes["institute"], nc.Attributes["type_instrument"], nc.Attributes["instrument_number"], nc.Attributes["pi"]) // write first line header on header file and ascii file fmt.Fprintf(fbuf_hdr, str) fmt.Fprintf(fbuf_ascii, str) // display on screen fmt.Printf("%s", str) // write physical parameters in second line str = "" for _, key := range hdr { fmt.Fprintf(fbuf_ascii, "%s ", key) fmt.Fprintf(debug, "%s ", key) } // append new line //fmt.Fprintln(fbuf_ascii, "\n") // write second line header on ascii file fmt.Fprintln(fbuf_ascii, str) // display on screen fmt.Printf("%s", str) // get data (slices) from nc struct len_1D := nc.Dimensions["TIME"] len_2D := nc.Dimensions["DEPTH"] time := nc.Variables_1D["TIME"].([]float64) lat := nc.Variables_1D["LATITUDE"].([]float64) lon := nc.Variables_1D["LONGITUDE"].([]float64) profile := nc.Variables_1D["PROFILE"].([]float64) bath := nc.Variables_1D["BATH"].([]float64) // loop over each profile for x := 0; x < len_1D; x++ { str = "" // write profile informations to ASCII data file with DEPTH = -1 t1 := NewTimeFromJulian(time[x]) t2 := NewTimeFromJulianDay(nc.Extras_f[fmt.Sprintf("ETDD:%d", int(profile[x]))], t1) // TODOS: adapt profile format to stationPrefixLength fmt.Fprintf(fbuf_ascii, "%05.0f %4d %f %f %f %s", profile[x], codeForProfile, t1.JulianDayOfYear(), lat[x], lon[x], t1.Format("20060102150405")) // write profile informations to header file, max depth CTD and // bathymetrie are in meters str = fmt.Sprintf("%05.0f %s %s %s %s %4.4g %4.4g %s %s %s\n", profile[x], t1.Format("02/01/2006 15:04:05"), t2.Format("02/01/2006 15:04:05"), DecimalPosition2String(lat[x], 0), DecimalPosition2String(lon[x], 0), nc.Extras_f[fmt.Sprintf("DEPTH:%d", int(profile[x]))], bath[x], nc.Extras_s[fmt.Sprintf("TYPECAST:%s", int(profile[x]))], cfg.Ctd.CruisePrefix+nc.Extras_s[fmt.Sprintf("PRFL_NAME:%d", int(profile[x]))]) // write profile information to header file fmt.Fprintf(fbuf_hdr, str) // display on screen fmt.Printf("%s", str) // fill last header columns with 1e36 for i := 0; i < len(hdr)-6; i++ { fmt.Fprintf(fbuf_ascii, " %g", 1e36) } fmt.Fprintln(fbuf_ascii) // add newline // loop over each level for y := 0; y < len_2D; y++ { // goto next profile when max depth reach if lib.GetData(nc.Variables_2D["PRES"])[x][y] >= nc.Extras_f[fmt.Sprintf("PRES:%d", int(profile[x]))] { continue } fmt.Fprintf(fbuf_ascii, "%05.0f ", profile[x]) // loop over each physical parameter (key) in the rigth order for _, key := range hdr { // if key not in map, goto next key if _, ok := nc.Variables_2D[key]; ok { // fill 2D slice data := lib.GetData(nc.Variables_2D[key])[x][y] // print data with it's format, change format for FillValue if data == 1e36 { fmt.Fprintf(fbuf_ascii, "%g ", data) } else { fmt.Fprintf(fbuf_ascii, map_format[key]+" ", data) } } } fmt.Fprintf(fbuf_ascii, "\n") } fbuf_ascii.Flush() fbuf_hdr.Flush() } }
// creates the NetCDF file following nc structure. //func WriteNetcdf(any interface{}) error { func WriteNetcdf(nc *lib.Nc, m *config.Map, ncType string) { // build filename filename := fmt.Sprintf("output/OS_%s%s_%s.nc", strings.ToUpper(nc.Attributes["cycle_mesure"]), strings.ToUpper(prefixAll), ncType) //fmt.Println(filename) // get roscop definition file for variables attributes var roscop = nc.Roscop // for k, v := range roscop { // fmt.Printf("%s: ", k) // fmt.Println(v) // } // os.Exit(0) fmt.Fprintf(echo, "writing netCDF: %s\n", filename) // get variables_1D size len_1D := nc.Dimensions["TIME"] len_2D := nc.Dimensions["DEPTH"] // Create a new NetCDF 3 file. The dataset is returned. ds, err := netcdf.CreateFile(filename, netcdf.CLOBBER) if err != nil { log.Fatal(err) } defer ds.Close() // Add the dimensions for our data to the dataset dim_1D := make([]netcdf.Dim, 1) dim_2D := make([]netcdf.Dim, 2) // dimensions for ROSCOP paremeters as DEPTH, PRES, TEMP, PSAL, etc dim_2D[0], err = ds.AddDim("TIME", uint64(len_1D)) if err != nil { log.Fatal(err) } dim_2D[1], err = ds.AddDim("DEPTH", uint64(len_2D)) if err != nil { log.Fatal(err) } // dimension for PROFILE, LATITUDE, LONGITUDE and BATH dim_1D[0] = dim_2D[0] // Add the variable to the dataset that will store our data map_1D := make(map[string]netcdf.Var) for key, _ := range nc.Variables_1D { v, err := ds.AddVar(key, netcdf.DOUBLE, dim_1D) if err != nil { log.Fatal(err) } map_1D[key] = v //initialise struct roscop with netcdf variable in reflect ways without knowing the form of the roscop struct Reflectroscop(roscop[key], map_1D[key]) } map_2D := make(map[string]netcdf.Var) // use the order list gave by split or splitAll (config file) because // the iteration order is not specified and is not guaranteed to be // the same from one iteration to the next in golang // for key, _ := range nc.Variables_2D { for _, key := range m.Hdr { // remove PRFL from the key list if key == "PRFL" { continue } v, err := ds.AddVar(key, netcdf.DOUBLE, dim_2D) if err != nil { log.Fatal(err) } map_2D[key] = v //initialise struct roscop with netcdf variable in reflect ways without knowing the form of the roscop struct Reflectroscop(roscop[key], map_2D[key]) } // defines global attributes for key, value := range nc.Attributes { a := ds.Attr(key) a.WriteBytes([]byte(value)) } // leave define mode in NetCDF3 ds.EndDef() // Create the data with the above dimensions and write it to the file. for key, value := range nc.Variables_1D { v := value.([]float64) fmt.Fprintf(echo, "writing %s: %d\n", key, len(v)) err = map_1D[key].WriteFloat64s(v) if err != nil { log.Fatal(err) } } // write data 2D (value.data) to netcdf variables // for key, value := range nc.Variables_2D { for _, key := range m.Hdr { // remove PRFL from the key list if key == "PRFL" { continue } value := nc.Variables_2D[key] i := 0 ht := len(lib.GetData(value)) wd := len(lib.GetData(value)[0]) fmt.Fprintf(echo, "writing %s: %d x %d\n", key, ht, wd) fmt.Fprintf(debug, "writing %s: %d x %d\n", key, ht, wd) // Write<type> netcdf methods need []<type>, [][]data will be flatten gopher := make([]float64, ht*wd) for x := 0; x < ht; x++ { for y := 0; y < wd; y++ { gopher[i] = lib.GetData(value)[x][y] i++ } } err = map_2D[key].WriteFloat64s(gopher) if err != nil { log.Fatal(err) } } fmt.Fprintf(echo, "writing %s done ...\n", filename) //return nil }