func secondPassTHERMO(nc *lib.Nc, m *config.Map, cfg toml.Configtoml, files []string, optDebug *bool) { regdata := regexp.MustCompile(cfg.Thecsas.Data) fmt.Fprintf(lib.Echo, "Second pass ...\n") // initialize profile var nbProfile int = 0 // loop over each files passed throw command line for _, file := range files { var line int = 0 fid, err := os.Open(file) if err != nil { log.Fatal(err) } defer fid.Close() // fmt.Printf("Read %s\n", file) // increment slice index Profile := GetProfileNumber(nc, nbProfile) nc.Variables_1D["PROFILE"] = append(nc.Variables_1D["PROFILE"].([]float64), Profile) scanner := bufio.NewScanner(fid) for scanner.Scan() { str := scanner.Text() match := regdata.MatchString(str) if match { // fill map data with information contain in read line str DecodeData(nc, m, str, Profile, file, line) // fill 2D slice for _, key := range m.Hdr { if key != "PRFL" { //fmt.Println("Line: ", line, "key: ", key, " data: ", m.Data[key]) lib.SetData(nc.Variables_2D[key], nbProfile, line, config.GetData(m.Data[key])) } } line++ } } if err := scanner.Err(); err != nil { log.Fatal(err) } nbProfile += 1 var t = lib.NewTimeFromString("Jan 02 2006 15:04:05", nc.Extras_s[fmt.Sprintf("Starttime:%d", int(Profile))]) v := t.Time2JulianDec() nc.Variables_1D["TIME"] = append(nc.Variables_1D["TIME"].([]float64), v) if v, err := lib.Position2Decimal(nc.Extras_s[fmt.Sprintf("Startlongpos:%d", int(Profile))]); err == nil { nc.Variables_1D["LONGITUDE"] = append(nc.Variables_1D["LONGITUDE"].([]float64), v) } if v, err := lib.Position2Decimal(nc.Extras_s[fmt.Sprintf("Startlatpos:%d", int(Profile))]); err == nil { nc.Variables_1D["LATITUDE"] = append(nc.Variables_1D["LATITUDE"].([]float64), v) } } }
// extract data from the line read in str with order gave by hash map_var // values: 1318 81.583900 3.000 2.983 29.5431 29.5464 5 ... // map_var: PRES:2 DEPTH:3 PSAL:21 DOX2:18 ... func DecodeData(nc *lib.Nc, m *config.Map, str string, profile float64, file string, line int) { var timestop string var Poslatstop string var Poslongstop string // split the string str using coma characters values := strings.Split(str, ",") nb_value := len(values) //extract time date := values[2] time := values[3] //extract pos lat_s := values[4] lat_deg := values[5] lat_min := values[6] long_s := values[7] long_deg := values[8] long_min := values[9] timestop = lib.ConvertDate(date + " " + time) Poslatstop = lat_deg + " " + lat_min + " " + lat_s Poslongstop = long_deg + " " + long_min + " " + long_s // for each physical parameter, extract its data from the rigth column // and save it in map data for key, column := range m.Map_var { if column > nb_value { log.Fatal(fmt.Sprintf("Error in func DecodeData() "+ "configuration mismatch\nFound %d values, and we try to use column %d", nb_value, column)) } if v, err := strconv.ParseFloat(values[column], 64); err == nil { m.Data[key] = v } else { log.Printf("Can't parse line: %d in file: %s\n", line, file) log.Fatal(err) } } if line == 0 { nc.Extras_s[fmt.Sprintf("Starttime:%d", int(profile))] = timestop nc.Extras_s[fmt.Sprintf("Startlatpos:%d", int(profile))] = Poslatstop nc.Extras_s[fmt.Sprintf("Startlongpos:%d", int(profile))] = Poslongstop } m.Data["PRFL"] = profile if v, err := lib.Position2Decimal(Poslatstop); err == nil { m.Data["LAT"] = v } if v, err := lib.Position2Decimal(Poslongstop); err == nil { m.Data["LONG"] = v } nc.Extras_s[fmt.Sprintf("Stopttime:%d", int(profile))] = timestop nc.Extras_s[fmt.Sprintf("Stoplatpos:%d", int(profile))] = Poslatstop nc.Extras_s[fmt.Sprintf("Stoplongpos:%d", int(profile))] = Poslongstop }
func WriteAscii(nc *lib.Nc, cfg toml.Configtoml, map_format map[string]string, hdr []string, inst string, prefixAll string) { // define 2 files, profiles header and data var asciiFilename string var lat2 string var latdecimal float64 var longdecimal float64 var long2 string // build filenames str := nc.Attributes["cycle_mesure"] str = strings.Replace(str, "\r", "", -1) headerFilename := fmt.Sprintf(cfg.Outputfile+"%s."+inst, strings.ToLower(str)) asciiFilename = fmt.Sprintf(cfg.Outputfile+"%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(lib.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) // loop over each profile for x := 0; x < len_1D; x++ { str = "" // write profile informations to ASCII data file with DEPTH = -1 t1 := lib.NewTimeFromJulian(time[x]) var t = lib.NewTimeFromString("Jan 02 2006 15:04:05", nc.Extras_s[fmt.Sprintf("Stopttime:%d", int(profile[x]))]) t2 := lib.NewTimeFromJulian(t.Time2JulianDec()) // 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")) if longdecimal, err := lib.Position2Decimal(nc.Extras_s[fmt.Sprintf("Stoplongpos:%d", int(profile[x]))]); err == nil { long2 = lib.DecimalPosition2String(longdecimal, 0) } if latdecimal, err := lib.Position2Decimal(nc.Extras_s[fmt.Sprintf("Stoplatpos:%d", int(profile[x]))]); err == nil { lat2 = lib.DecimalPosition2String(latdecimal, 0) } // write profile informations to header file str = fmt.Sprintf("%05.0f %s %s %s %s %s %s %s %s\n", profile[x], t1.Format("02/01/2006 15:04:05"), t2.Format("02/01/2006 15:04:05"), lib.DecimalPosition2String(lat[x], 0), lib.DecimalPosition2String(lon[x], 0), lat2, long2, nc.Extras_s[fmt.Sprintf("TYPECAST:%s", int(profile[x]))], nc.Extras_s[fmt.Sprintf("PRFL_NAME:%d", int(profile[x]))]+cfg.Thermo.CruisePrefix) // 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["LAT"])[x][y] == latdecimal && lib.GetData(nc.Variables_2D["LONG"])[x][y] == longdecimal { 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 { if strings.ContainsAny(map_format[key], "lf") { res := strings.Split(map_format[key], "l") map_format[key] = strings.Join(res, "") } fmt.Fprintf(fbuf_ascii, map_format[key], data) } } } fmt.Fprintf(fbuf_ascii, "\n") } fbuf_ascii.Flush() fbuf_hdr.Flush() } }
func DecodeHeader(nc *lib.Nc, cfg toml.Configtoml, str string, profile float64, optDebug *bool) { regCruise := regexp.MustCompile(cfg.Seabird.Cruise) regShip := regexp.MustCompile(cfg.Seabird.Ship) regStation := regexp.MustCompile(cfg.Seabird.Station) regType := regexp.MustCompile(cfg.Seabird.Type) regOperator := regexp.MustCompile(cfg.Seabird.Operator) regBottomDepth := regexp.MustCompile(cfg.Seabird.BottomDepth) regDummyBottomDepth := regexp.MustCompile(cfg.Seabird.DummyBottomDepth) regSystemTime := regexp.MustCompile(cfg.Seabird.SystemTime) regNmeaLatitude := regexp.MustCompile(cfg.Seabird.Latitude) regNmeaLongitude := regexp.MustCompile(cfg.Seabird.Longitude) switch { // decode Systeme Upload Time case regSystemTime.MatchString(str): res := regSystemTime.FindStringSubmatch(str) value := res[1] fmt.Fprintf(lib.Debug, "%s -> ", value) // create new Time object, see tools.go var t = lib.NewTimeFromString("Jan 02 2006 15:04:05", value) v := t.Time2JulianDec() nc.Variables_1D["TIME"] = append(nc.Variables_1D["TIME"].([]float64), v) case regNmeaLatitude.MatchString(str): if v, err := lib.Position2Decimal(str); err == nil { nc.Variables_1D["LATITUDE"] = append(nc.Variables_1D["LATITUDE"].([]float64), v) } else { nc.Variables_1D["LATITUDE"] = append(nc.Variables_1D["LATITUDE"].([]float64), 1e36) } case regNmeaLongitude.MatchString(str): if v, err := lib.Position2Decimal(str); err == nil { nc.Variables_1D["LONGITUDE"] = append(nc.Variables_1D["LONGITUDE"].([]float64), v) } else { nc.Variables_1D["LONGITUDE"] = append(nc.Variables_1D["LONGITUDE"].([]float64), 1e36) } case regCruise.MatchString(str): res := regCruise.FindStringSubmatch(str) value := res[1] fmt.Fprintln(lib.Debug, value) nc.Attributes["cycle_mesure"] = value case regShip.MatchString(str): res := regShip.FindStringSubmatch(str) value := res[1] fmt.Fprintln(lib.Debug, value) nc.Attributes["plateforme"] = value case regStation.MatchString(str): res := regStation.FindStringSubmatch(str) value := res[1] if v, err := strconv.ParseFloat(value, 64); err == nil { fmt.Fprintln(lib.Debug, v) // ch // format := "%0" + cfg.Ctd.StationPrefixLength + ".0f" // p := fmt.Sprintf(format, profile) // //s := fmt.Sprintf(format, v) // fmt.Println(p, v) // if p != v { // fmt.Printf("Warning: profile for header differ from file name: %s <=> %s\n", p, v) // } nc.Variables_1D["PROFILE"] = append(nc.Variables_1D["PROFILE"].([]float64), profile) } else { nc.Variables_1D["PROFILE"] = append(nc.Variables_1D["PROFILE"].([]float64), 1e36) } fmt.Println(value) case regBottomDepth.MatchString(str): res := regBottomDepth.FindStringSubmatch(str) value := res[1] if v, err := strconv.ParseFloat(value, 64); err == nil { fmt.Fprintf(lib.Debug, "Bath: %f\n", v) nc.Variables_1D["BATH"] = append(nc.Variables_1D["BATH"].([]float64), v) } else { fmt.Fprintf(lib.Debug, "Bath: %f\n", v) nc.Variables_1D["BATH"] = append(nc.Variables_1D["BATH"].([]float64), 1e36) } case regDummyBottomDepth.MatchString(str): //? nc.Variables_1D["BATH"] = append(nc.Variables_1D["BATH"].([]float64), 1e36) fmt.Fprintf(lib.Debug, "Bath: %g\n", 1e36) fmt.Println("1e36") case regOperator.MatchString(str): res := regOperator.FindStringSubmatch(str) value := res[1] nc.Attributes["operator"] = value // TODOS: uncomment, add optionnal value from seabird header case regType.MatchString(str): res := regType.FindStringSubmatch(str) value := strings.ToUpper(res[1]) // convert to upper case var v float64 switch value { case "PHY": v = float64(lib.PHY) case "GEO": v = float64(lib.GEO) case "BIO": v = float64(lib.BIO) default: v = float64(lib.UNKNOW) } nc.Variables_1D["TYPECAST"] = append(nc.Variables_1D["TYPECAST"].([]float64), v) nc.Extras_s[fmt.Sprintf("TYPECAST:%s", int(profile))] = value } }