This commit is contained in:
softlandia 2020-06-28 21:46:04 +04:00
Родитель d236bf29cd
Коммит 769b1052a0
26 изменённых файлов: 394 добавлений и 374 удалений

Просмотреть файл

@ -1,4 +1,8 @@
## ver 0.2.3 // 2020.06.28 ##
## ver 0.2.4 // 2020.06.28 ##
- полностью переведено на хранение параметров в специализированных контейнерах, прямые поля параметров удалены
## ver 0.2.3 // 2020.06.28 ##
- все тесты проходят, версия подготовленная к переходу от прямых параметров к использованию хранящихся в специализированных контейнерах

Просмотреть файл

@ -54,6 +54,11 @@ lasin
coverage 91%
folder "data" contain files for testing, no remove/change/add
## technical info ##
if las file contane duplicated of any parameter, then used first
on curve section used all curves name, duplicated renamed
## warnings generated when reading a LAS file ##
### warning format ###

Просмотреть файл

@ -8,7 +8,7 @@
STOP.M 1660.000000:
STEP.M -0.1250:
STEP.M -0.1200:
NULL. -999.2500:
NULL. -999.2111:
COMP. COMPANY: # ANY OIL COMPANY LTD.
WELL. WELL: ANY ET AL OIL WELL #12
FLD . FIELD: EDAM

Просмотреть файл

@ -1,8 +1,3 @@
#
# las ¤«ï ¯à®¢¥àª¨  ¢â®¬ â¨ç¥áª®£® 㢥«¨ç¥­¨ï á« ©á®¢ ¯à¨ ç⥭¨¨
# à áè¨à¥­¨¥ ¤®«¦­® ¡ëâì ¢ë¯®«­¥­® ¤¢  à § , ¤¢¥ § ¯¨á¨ ¢ "las.warning.md"
#
~Version Information
VERS. 1.20: CP866 CWLS log ASCII Standard - VERSION 1.20
WRAP. NO : One line per depth step

Просмотреть файл

@ -1,6 +1,6 @@
**file: data\more_20_warnings.las**
0, line: 24, "__WRN__ STRT: 0.000 == STOP: 0.000"
1, line: 24, "__WRN__ STEP parameter equal 0"
0, line: 24, "__WRN__ STEP parameter equal 0"
1, line: 24, "__WRN__ STRT: 0.000 == STOP: 0.000"
2, line: 24, "error convert string: '6.2.24' to number, set to NULL"
3, line: 25, "line contains 5 columns, expected: 6"
4, line: 25, "error convert string: '528.07202215.58' to number, set to NULL"

Просмотреть файл

@ -1,38 +0,0 @@
0, 24, "__WRN__ STEP parameter equal 0"
1, 24, "__WRN__ STRT: 0.000 == STOP: 0.000"
2, 24, "error convert string: '6.2.24' to number, set to NULL"
3, 25, "line contains 5 columns, expected: 6"
4, 25, "error convert string: '528.07202215.58' to number, set to NULL"
5, 25, "for column 6 data not present, value set to NULL"
6, 27, "error convert string: '6.2.24' to number, set to NULL"
7, 29, "error convert string: '5.97.5' to number, set to NULL"
8, 31, "error convert string: '6.47.3' to number, set to NULL"
9, 33, "depth not monotony"
10, 33, "error convert string: '5.97.5' to number, set to NULL"
11, 35, "depth not monotony"
12, 35, "error convert string: '5.47.7' to number, set to NULL"
13, 37, "depth not monotony"
14, 37, "error convert string: '4.7.3' to number, set to NULL"
15, 38, "error convert string: '4.7.3' to number, set to NULL"
16, 40, "line contains 1 columns, expected: 6"
17, 40, "depth not monotony"
18, 40, "for column 2 data not present, value set to NULL"
19, 40, "for column 3 data not present, value set to NULL"
20, 40, "for column 4 data not present, value set to NULL"
21, 40, "for column 5 data not present, value set to NULL"
22, 40, "for column 6 data not present, value set to NULL"
23, 41, "line contains 9 columns, expected: 6"
24, 41, "depth not monotony"
25, 42, "depth not monotony"
26, 43, "depth not monotony"
27, 45, "dept:'--177' not numeric, line ignore"
28, 46, "depth not monotony"
29, 48, "depth not monotony"
30, 49, "depth not monotony"
31, 50, "depth not monotony"
32, 54, "line contains 13 columns, expected: 6"
33, 54, "depth not monotony"
34, 55, "line contains 7 columns, expected: 6"
35, 55, "dept:'-x' not numeric, line ignore"
36, 56, "line contains 5 columns, expected: 6"
37, 56, "dept:'a1' not numeric, line ignore"

Просмотреть файл

@ -2,4 +2,4 @@
this example program uses the softlandia / glasio package to read a LAS file
the program reads the input las file and displays warnings on the console
the program reads the input las file and put warnings to the console

Просмотреть файл

@ -1,15 +1,10 @@
#
# las ¤«ï ¯à®¢¥àª¨  ¢â®¬ â¨ç¥áª®£® 㢥«¨ç¥­¨ï á« ©á®¢ ¯à¨ ç⥭¨¨
# à áè¨à¥­¨¥ ¤®«¦­® ¡ëâì ¢ë¯®«­¥­® ¤¢  à § , ¤¢¥ § ¯¨á¨ ¢ "las.warning.md"
#
~Version Information
VERS. 1.20: cp_866 CWLS log ASCII Standard - VERSION 1.20
VERS. 1.20: cp_866
WRAP. NO : One line per depth step
~Well Information
STRT .M 1.0 : Start depth
STOP .M 1.0 : Stop depth
STEP .M 0.10 : Step
STRT .M 0.0 : Start depth
STOP .M 0.0 : Stop depth
STEP .M 0.0 : Step
NULL . -9999.00 : Null value
WELL . WELL : 12-‘¯«®è­ ï
~Curve Information

Просмотреть файл

@ -7,7 +7,7 @@ import (
"github.com/softlandia/glasio"
)
// Sample
// Sample
// read one file and print to stdout all warnings:
// warning number, number of line in las file, message
func main() {

Просмотреть файл

@ -2,8 +2,8 @@
VERS. 2.0 : glas (c) softlandia@gmail.com
WRAP. NO : ONE LINE PER DEPTH STEP
~Well information
STRT.M 1.000 :START DEPTH
STOP.M 1.000 :STOP DEPTH
STRT.M 0.000 :START DEPTH
STOP.M 0.000 :STOP DEPTH
STEP.M 0.100 :STEP
NULL. -9999.000 :NULL VALUE
WELL. 12-Ñïëîøíàÿ :WELL

24
examples/simple/ex01.las Normal file
Просмотреть файл

@ -0,0 +1,24 @@
~Version Information
VERS. 1.20: cp_866
WRAP. NO : One line per depth step
~Well Information
STRT .M 0.0 : Start depth
STOP .M 0.0 : Stop depth
STEP .M 0.0 : Step
NULL . -9999.00 : Null value
WELL . WELL : 12-‘¯«®è­ ï
~Curve Information
DEPT .M : 1 DEPTH
 <EFBFBD> .¤.¥¤. :
 <EFBFBD>.ãá«.¥¤. : et
 <EFBFBD> . :
~Parameter Information
EKB .M 72.7 : Elevation,Kelly Bushing
~ASCII Log Data
1.000 -9999.000 -9999.000 2.000
1.100 -9999.000 11.535 1.000
1.200 -9999.000 -9999.000 5.000
1.300 0.762 -9999.000 5.000
1.400 0.707 16.053 1.000
1.500 0.000 -9999.000 0.000
1.600 0.000 -9999.000 -9999.000

Просмотреть файл

@ -0,0 +1,7 @@
**file: ex01.las**
0, line: 18, "__WRN__ STEP parameter equal 0"
1, line: 18, "__WRN__ STRT: 0.000 == STOP: 0.000"
2, line: 21, "depth not monotony"
3, line: 22, "depth not monotony"
4, line: 23, "depth not monotony"

Просмотреть файл

@ -1,6 +0,0 @@
**file: expand_points_01.las**
0, line: 23, "__WRN__ STRT: 1.000 == STOP: 1.000"
1, line: 26, "depth not monotony"
2, line: 27, "depth not monotony"
3, line: 28, "depth not monotony"

Просмотреть файл

@ -7,6 +7,7 @@ package main
import (
"fmt"
"log"
"strings"
"github.com/softlandia/cpd"
@ -15,24 +16,24 @@ import (
func main() {
test1()
test2()
readAndSave()
makeAndSave()
}
// reads las file
// writes messages file
// reads las file
// writes messages file
// and writes the repaired las files
func test1() {
func readAndSave() {
//test file "1.las"
las := glasio.NewLas()
n, err := las.Open("expand_points_01.las")
n, err := las.Open("ex01.las")
if n != 7 {
fmt.Printf("TEST read expand_points_01.las ERROR, n = %d, must 7\n", n)
fmt.Printf("TEST read ex01.las ERROR, n = %d, must 7\n", n)
fmt.Println(err)
}
las.SaveWarning("expand_points_01.warning.md")
las.SaveWarning("ex01.warning.md")
err = las.Save("expand_points_01+.las")
err = las.Save("ex01+.las")
if err != nil {
fmt.Println("TEST save -1.las ERROR: ", err)
}
@ -40,24 +41,30 @@ func test1() {
las = nil
}
// writes simple las file
func test2() {
var s = `~W
NULL. -99.99:
STRT.m 00.21:
STOP.m 10.01:
STEP.m 00.01:
WELL. Примерная-101 / бис:`
// make las object from string in memory and writes simple las file
func makeAndSave() {
//make object, the file will be saved in encoding CP866
las := glasio.NewLas(cpd.CP866)
las.Null = -99.99
las.Rkb = 100.01
las.Strt = 0.201
las.Stop = 10.01
las.Step = 0.01
las.Well = "Примерная-101/бис"
//parse string s as las file, only section ~W
las.Load(strings.NewReader(s))
//make curve depth
d := glasio.NewLasCurve("DEPT", las)
sp := glasio.NewLasCurve("SP.mV :spontaniously", las)
//make curve sp
sp := glasio.NewLasCurve("SP.mV", las)
for i := 0; i < 5; i++ {
d.D = append(d.D, float64(i))
sp.D = append(sp.D, float64(i))
sp.V = append(sp.V, float64(i) / 100)
d.D = append(d.D, las.STRT()+las.STEP()*float64(i))
sp.D = append(sp.D, d.D[i])
sp.V = append(sp.V, float64(i)/100)
}
las.Logs = append(las.Logs, d)
las.Logs = append(las.Logs, sp)
err := las.Save("empty.las")
err := las.Save("simple.las")
log.Printf("err: %v", err)
}

Просмотреть файл

@ -2,18 +2,18 @@
VERS. 2.0 : glas (c) softlandia@gmail.com
WRAP. NO : ONE LINE PER DEPTH STEP
~Well information
STRT.M 0.201 :START DEPTH
STRT.M 0.210 :START DEPTH
STOP.M 10.010 :STOP DEPTH
STEP.M 0.010 :STEP
NULL. -99.990 :NULL VALUE
WELL. <20>ਬ¥à­ ï-101/¡¨á :WELL
WELL. <20>ਬ¥à­ ï-101 / ¡¨á :WELL
~Curve Information Section
DEPT.M :
SP.mV :
~ASCII Log Data
# DEPT | SP |
0.0000 0.0000
1.0000 0.0100
2.0000 0.0200
3.0000 0.0300
4.0000 0.0400
0.2100 0.0000
0.2200 0.0100
0.2300 0.0200
0.2400 0.0300
0.2500 0.0400

235
las.go
Просмотреть файл

@ -25,30 +25,20 @@ import (
// Las - class to store las file
// input code page autodetect
// at read file always code page converted to UTF
// at save file code page converted to specifyed in Las.toCodePage
// at save file code page converted to specifyed in Las.oCodepage
//TODO add pointer to cfg
//TODO при создании объекта las есть возможность указать кодировку записи, нужна возможность указать явно кодировку чтения
type Las struct {
rows []string // buffer for read source file, only converted to UTF-8 no any othe change
nRows int // actually count of lines in source file
FileName string // file name from load
File *os.File // the file from which we are reading
Reader io.Reader // reader created from File, provides decode from codepage to UTF-8
scanner *bufio.Scanner // scanner
Ver float64 // version 1.0, 1.2 or 2.0
Wrap string // YES || NO
Strt float64 // start depth
Stop float64 // stop depth
Step float64 // depth step
Null float64 // value interpreted as empty
Well string // well name
Rkb float64 // altitude KB
Logs LasCurves // store all logs
LogDic *map[string]string // external dictionary of standart log name - mnemonics
VocDic *map[string]string // external vocabulary dictionary of log mnemonic
Warnings TLasWarnings // slice of warnings occure on read or write
oCodepage cpd.IDCodePage // codepage to save, default xlib.CpWindows1251. to special value, specify at make: NewLas(cp...)
iDuplicate int // index of duplicated mnemonic, increase by 1 if found duplicated
currentLine int // index of current line in readed file
maxWarningCount int // default maximum warning count
stdNull float64 // default null value
@ -72,17 +62,17 @@ var (
//method for get values from header containers ////////////////
func (las *Las) parFloat(name string, defValue float64) float64 {
func (las *Las) parFloat(sec HeaderSection, name string, defValue float64) float64 {
v := defValue
if p, ok := las.VerSec.params[name]; ok {
if p, ok := sec.params[name]; ok {
v, _ = strconv.ParseFloat(p.Val, 64)
}
return v
}
func (las *Las) parStr(name, defValue string) string {
func (las *Las) parStr(sec HeaderSection, name, defValue string) string {
v := defValue
if p, ok := las.VerSec.params[name]; ok {
if p, ok := sec.params[name]; ok {
v = p.Val
}
return v
@ -91,54 +81,51 @@ func (las *Las) parStr(name, defValue string) string {
// NULL - return null value of las file as float64
// if parameter NULL in las file not exist, then return StdNull (by default -999.25)
func (las *Las) NULL() float64 {
return las.parFloat("NULL", StdNull)
return las.parFloat(las.WelSec, "NULL", StdNull)
}
// STOP - return depth stop value of las file as float64
// if parameter STOP in las file not exist, then return StdNull (by default -999.25)
func (las *Las) STOP() float64 {
return las.parFloat("STOP", StdNull)
return las.parFloat(las.WelSec, "STOP", StdNull)
}
// STRT - return depth start value of las file as float64
// if parameter NULL in las file not exist, then return StdNull (by default -999.25)
func (las *Las) STRT() float64 {
return las.parFloat("STRT", StdNull)
return las.parFloat(las.WelSec, "STRT", StdNull)
}
// STEP - return depth step value of las file as float64
// if parameter not exist, then return StdNull (by default -999.25)
func (las *Las) STEP() float64 {
return las.parFloat("STEP", StdNull)
return las.parFloat(las.WelSec, "STEP", StdNull)
}
// VERS - return version of las file as float64
// if parameter VERS in las file not exist, then return 2.0
func (las *Las) VERS() float64 {
return las.parFloat("VERS", 2.0)
return las.parFloat(las.VerSec, "VERS", 2.0)
}
// WRAP - return wrap parameter of las file
// if parameter not exist, then return "NO"
func (las *Las) WRAP() string {
return las.parStr("WRAP", "NO")
return las.parStr(las.VerSec, "WRAP", "NO")
}
// WELL - return well name
// if parameter WELL in las file not exist, then return "--"
func (las *Las) WELL() string {
return las.parStr("WELL", "--")
return las.parStr(las.WelSec, "WELL", "")
}
//NewLas - make new object Las class
//autodetect code page at load file
//code page to save by default is cpd.CP1251
func NewLas(outputCP ...cpd.IDCodePage) *Las {
las := &Las{} //new(Las)
las.Ver = 2.0 //<VER>
las.Wrap = "NO"
las.nRows = ExpPoints
las.rows = make([]string, 0, las.nRows)
las := new(Las)
las.rows = make([]string, 0, ExpPoints /*las.nRows*/)
las.Logs = make([]LasCurve, 0)
las.VerSec = NewVerSection()
las.WelSec = NewWelSection()
@ -147,9 +134,6 @@ func NewLas(outputCP ...cpd.IDCodePage) *Las {
las.OthSec = NewOthSection()
las.maxWarningCount = MaxWarningCount
las.stdNull = StdNull
las.Strt = StdNull
las.Stop = StdNull
las.Step = StdNull
if len(outputCP) > 0 {
las.oCodepage = outputCP[0]
} else {
@ -159,14 +143,12 @@ func NewLas(outputCP ...cpd.IDCodePage) *Las {
las.LogDic = nil
//external log dictionary
las.VocDic = nil
//счётчик повторяющихся мнемоник, увеличивается каждый раз на 1, используется при переименовании мнемоники
las.iDuplicate = 0
return las
}
// IsWraped - return true if WRAP == YES
func (las *Las) IsWraped() bool {
return strings.Contains(strings.ToUpper(las.Wrap), "Y")
return strings.Contains(strings.ToUpper(las.WRAP()), "Y")
}
// GetRows - get internal field 'rows'
@ -182,25 +164,20 @@ func (las *Las) ReadRows() int {
return len(las.rows)
}
// Open -
func (las *Las) Open(fileName string) (int, error) {
// Load - load las from reader
// you can make reader from string or othe containers and send as input parameters
func (las *Las) Load(reader io.Reader) (int, error) {
var err error
las.File, err = os.Open(fileName)
if err != nil {
return 0, err //FATAL error - file not exist
if reader == nil {
return 0, errors.New("Load received nil reader")
}
defer las.File.Close()
las.FileName = fileName
//create Reader, this reader decode to UTF-8
las.Reader, err = cpd.NewReader(las.File)
//create Reader, this reader decode to UTF-8 from reader
las.Reader, err = cpd.NewReader(reader)
if err != nil {
return 0, err //FATAL error - file cannot be decoded to UTF-8
}
// prepare file to read
las.scanner = bufio.NewScanner(las.Reader)
// ePoints - содержит теперь количество строк в las файле
// соответственно слайсы для хранения кривых будут создаваться этой длины
//las.ePoints = las.ReadRows()
las.ReadRows()
m, _ := las.LoadHeader()
stdChecker := NewStdChecker()
@ -215,7 +192,7 @@ func (las *Las) Open(fileName string) (int, error) {
}
if r.strtWrong() {
h := las.GetStrtFromData() // return las.Null if cannot find strt in the data section.
if h == las.Null {
if h == las.NULL() {
las.addWarning(TWarning{directOnRead, lasSecWellInfo, -1, fmt.Sprint("__WRN__ STRT parameter on data is wrong setting to 0")})
las.setStrt(0)
}
@ -223,7 +200,7 @@ func (las *Las) Open(fileName string) (int, error) {
}
if r.stepWrong() {
h := las.GetStepFromData() // return las.Null if cannot calculate step from data
if h == las.Null {
if h == las.NULL() {
las.addWarning(TWarning{directOnRead, lasSecWellInfo, las.currentLine, fmt.Sprint("__WRN__ STEP parameter on data is wrong")})
}
las.setStep(h)
@ -231,9 +208,20 @@ func (las *Las) Open(fileName string) (int, error) {
return las.LoadDataSec(m)
}
// Open - read las file
func (las *Las) Open(fileName string) (int, error) {
var err error
las.File, err = os.Open(fileName)
if err != nil {
return 0, err //FATAL error - file not exist
}
defer las.File.Close()
las.FileName = fileName
return las.Load(las.File)
}
/*LoadHeader - read las file and load all section before ~A
returns the row number with which the data section begins, until return nil in any case
secName: 0 - empty, 1 - Version, 2 - Well info, 3 - Curve info, 4 - A data
1. читаем строку
2. если коммент или пустая в игнор
3. если начало секции, определяем какой
@ -242,63 +230,55 @@ func (las *Las) Open(fileName string) (int, error) {
*/
func (las *Las) LoadHeader() (int, error) {
var (
err error
sec HeaderSection
)
secNum := 0
//secNum := 0
las.currentLine = 0
for i, s := range las.rows {
for _, s := range las.rows {
s = strings.TrimSpace(s)
las.currentLine++
if isIgnoredLine(s) {
continue
}
if s[0] == '~' { //start new section
secNum = las.selectSection(rune(s[1]))
if secNum == lasSecData {
if las.isDataSection(rune(s[1])) {
break // reached the data section, stop load header
}
sec = las.section(rune(s[1]))
continue
}
//not comment, not empty and not new section => parameter, read it
err = las.ReadParameter(s, secNum)
p, _ := sec.parse(s, las.currentLine)
p.Name = sec.uniqueName(p.Name)
p, w := sec.parse(s, las.currentLine)
if !w.Empty() {
las.addWarning(w)
}
p.Name = sec.uniqueName(p.Name) //TODO if a duplicate of any parameter is detected, a warning should be generated
sec.params[p.Name] = p
if err != nil {
las.addWarning(TWarning{directOnRead, secNum, i, fmt.Sprintf("param: '%s' error: %v", s, err)})
if sec.name == 'C' { //for ~Curve section need additional actions
err := las.readCurveParam(s) //make new curve from "s" and store to container "Logs"
if err != nil {
las.addWarning(TWarning{directOnRead, 3, las.currentLine, fmt.Sprintf("param: '%s' error: %v", s, err)})
}
}
}
return las.currentLine, nil
}
// selectSection - analize first char after ~
// isDataSection - return true if data section reached
func (las *Las) isDataSection(r rune) bool {
return (r == 0x41) || (r == 0x61)
}
// ~V - section vertion
// ~W - well info section
// ~C - curve info section
// ~A - data section
func (las *Las) selectSection(r rune) int {
switch r {
case 0x76, 0x56: //86, 118: //V, v
return lasSecVersion //version section
case 0x77, 0x57: //W, w
return lasSecWellInfo //well info section
case 0x43, 0x63: //C, c
return lasSecCurInfo //curve section
case 0x41, 0x61: //A, a
return lasSecData //data section
default:
return lasSecIgnore
}
}
func (las *Las) section(r rune) HeaderSection {
switch r {
case 0x56, 0x76: //V, v
return las.VerSec //version section
case 0x57, 0x77: //W, w
if las.Ver < 2.0 {
if las.VERS() < 2.0 {
las.WelSec.parse = welParse12 //change parser, by default using parser 2.0
}
return las.WelSec //well info section
@ -318,62 +298,11 @@ func (las *Las) storeHeaderWarning(chkResults CheckResults) {
}
}
// ReadParameter - read one parameter
func (las *Las) ReadParameter(s string, secNum int) error {
switch secNum {
case lasSecVersion:
return las.readVersionParam(s)
case lasSecWellInfo:
return las.ReadWellParam(s)
case lasSecCurInfo:
return las.readCurveParam(s)
}
return nil
}
func (las *Las) readVersionParam(s string) error {
var err error
p := NewHeaderParam(s, 0)
switch p.Name {
case "VERS":
las.Ver, err = strconv.ParseFloat(p.Val, 64)
case "WRAP":
las.Wrap = p.Val
}
return err
}
//ReadWellParam - read parameter from WELL section
func (las *Las) ReadWellParam(s string) error {
var err error
p := NewHeaderParam(s, 0)
switch p.Name {
case "STRT":
las.Strt, err = strconv.ParseFloat(p.Val, 64)
case "STOP":
las.Stop, err = strconv.ParseFloat(p.Val, 64)
case "STEP":
las.Step, err = strconv.ParseFloat(p.Val, 64)
case "NULL":
las.Null, err = strconv.ParseFloat(p.Val, 64)
case "WELL":
if las.Ver < 2.0 {
las.Well = p.Desc
} else {
las.Well = wellNameFromParam(p)
}
}
if err != nil {
las.addWarning(TWarning{directOnRead, lasSecWellInfo, -1, fmt.Sprintf("detected param: %v, unit:%v, value: %v\n", p.Name, p.Unit, p.Val)})
}
return err
}
//Разбор одной строки с мнемоникой каротажа
//Разбираем а потом сохраняем в slice
//Каждый каротаж характеризуется тремя именами
//Name - имя каротажа, повторятся не может, если есть повторение, то Name строится добавлением к IName индекса
//IName - имя каротажа в исходном файле, может повторятся
//Name - ключ в map хранилище, повторятся не может. если в исходном есть повторение, то Name строится добавлением к IName индекса
//Mnemonic - мнемоника, берётся из словаря, если в словаре не найдено, то ""
func (las *Las) readCurveParam(s string) error {
l := NewLasCurve(s, las)
@ -398,9 +327,9 @@ func (las *Las) LoadDataSec(m int) (int, error) {
err error
dept float64
)
n := len(las.Logs) // количество каротажей, столько колонок данных ожидаем
dataRows := las.rows[m:] // reslice to lines with data only
nullAsStr := strconv.FormatFloat(las.Null, 'f', 5, 64) // Null as string
n := len(las.Logs) // количество каротажей, столько колонок данных ожидаем
dataRows := las.rows[m:] // reslice to lines with data only
nullAsStr := strconv.FormatFloat(las.NULL(), 'f', 5, 64) // Null as string
las.currentLine = m - 1
for _, line := range dataRows {
las.currentLine++
@ -441,7 +370,7 @@ func (las *Las) LoadDataSec(m int) (int, error) {
v, err = strconv.ParseFloat(s, 64)
if err != nil {
las.addWarning(TWarning{directOnRead, lasSecData, las.currentLine, fmt.Sprintf("error convert string: '%s' to number, set to NULL", s)})
v = las.Null
v = las.NULL()
}
las.Logs[j].D = append(las.Logs[j].D, dept)
las.Logs[j].V = append(las.Logs[j].V, v)
@ -510,11 +439,11 @@ func (las *Las) SaveToBuf(useMnemonic bool) ([]byte, error) {
fmt.Fprintf(&b, _LasVersion, 2.0) //file is always saved in 2.0 format
fmt.Fprint(&b, _LasWrap)
fmt.Fprint(&b, _LasWellInfoSec)
fmt.Fprintf(&b, _LasStrt, las.Strt)
fmt.Fprintf(&b, _LasStop, las.Stop)
fmt.Fprintf(&b, _LasStep, las.Step)
fmt.Fprintf(&b, _LasNull, las.Null)
fmt.Fprintf(&b, _LasWell, las.Well)
fmt.Fprintf(&b, _LasStrt, las.STRT())
fmt.Fprintf(&b, _LasStop, las.STOP())
fmt.Fprintf(&b, _LasStep, las.STEP())
fmt.Fprintf(&b, _LasNull, las.NULL())
fmt.Fprintf(&b, _LasWell, las.WELL())
fmt.Fprint(&b, _LasCurvSec)
fmt.Fprint(&b, _LasCurvDept)
@ -554,13 +483,13 @@ func (las *Las) IsEmpty() bool {
func (las *Las) GetStrtFromData() float64 {
iFile, err := os.Open(las.FileName)
if err != nil {
return las.Null //не обрабатывается в тесте
return las.NULL() //не обрабатывается в тесте
}
defer iFile.Close()
_, iScanner, err := xlib.SeekFileStop(las.FileName, "~A")
if (err != nil) || (iScanner == nil) {
return las.Null //не обрабатывается в тесте
return las.NULL() //не обрабатывается в тесте
}
s := ""
@ -576,12 +505,12 @@ func (las *Las) GetStrtFromData() float64 {
}
dept1, err = strconv.ParseFloat(s[:k], 64)
if err != nil {
return las.Null //не обрабатывается в тесте
return las.NULL() //не обрабатывается в тесте
}
return dept1
}
//если мы попали сюда, то всё грусно, в файле после ~A не нашлось двух строчек с данными... или пустые строчки или комменты
return las.Null
return las.NULL()
}
// GetStepFromData - return step from data section
@ -591,13 +520,13 @@ func (las *Las) GetStrtFromData() float64 {
func (las *Las) GetStepFromData() float64 {
iFile, err := os.Open(las.FileName)
if err != nil {
return las.Null //не обрабатывается в тесте
return las.NULL() //не обрабатывается в тесте
}
defer iFile.Close()
_, iScanner, err := xlib.SeekFileStop(las.FileName, "~A")
if (err != nil) || (iScanner == nil) {
return las.Null
return las.NULL()
}
s := ""
@ -616,7 +545,7 @@ func (las *Las) GetStepFromData() float64 {
dept1, err = strconv.ParseFloat(s[:k], 64)
if err != nil {
// case if the data row in the first position (dept place) contains not a number
return las.Null
return las.NULL()
}
j++
if j == 2 {
@ -626,42 +555,42 @@ func (las *Las) GetStepFromData() float64 {
dept2 = dept1
}
//bad case, data section not contain two rows with depth
return las.Null //не обрабатывается в тесте
return las.NULL() //не обрабатывается в тесте
}
func (las *Las) setStep(h float64) {
las.Step = h
las.WelSec.params["STEP"] = HeaderParam{strconv.FormatFloat(h, 'f', -1, 64), "STEP", "", "", "", "step of index", 8}
}
func (las *Las) setStrt(strt float64) {
las.Strt = strt
las.WelSec.params["STRT"] = HeaderParam{strconv.FormatFloat(strt, 'f', -1, 64), "STRT", "", "", "", "first index value", 6}
}
// IsStrtEmpty - return true if parameter Strt not exist in file
func (las *Las) IsStrtEmpty() bool {
return las.Strt == StdNull
return las.STRT() == StdNull
}
// IsStopEmpty - return true if parameter Stop not exist in file
func (las *Las) IsStopEmpty() bool {
return las.Stop == StdNull
return las.STOP() == StdNull
}
// IsStepEmpty - return true if parameter Step not exist in file
func (las *Las) IsStepEmpty() bool {
return las.Step == StdNull
return las.STEP() == StdNull
}
// SetNull - change parameter NULL in WELL INFO section and in all logs
func (las *Las) SetNull(aNull float64) {
func (las *Las) SetNull(null float64) {
for _, l := range las.Logs { //loop by logs
for i := range l.V { //loop by dept step
if l.V[i] == las.Null {
l.V[i] = aNull
if l.V[i] == las.NULL() {
l.V[i] = null
}
}
}
las.Null = aNull
las.WelSec.params["NULL"] = HeaderParam{strconv.FormatFloat(null, 'f', -1, 64), "NULL", "", "", "", "null value", las.WelSec.params["NULL"].lineNo}
}
// SaveWarning - save to file all warning

Просмотреть файл

@ -70,16 +70,6 @@ func (crs CheckResults) wellWrong() bool {
return ok
}
// isFatal - return true if CheckResults contains at least one check result with fatal error
func (crs CheckResults) isFatal() bool {
for _, c := range crs {
if c.err != nil {
return true
}
}
return false
}
// fatal - return first not nil error if CheckResults contains at least one check result with fatal error
func (crs CheckResults) fatal() error {
for _, c := range crs {
@ -99,7 +89,7 @@ type Checker map[string]Check
// если проверка прошла безошибочно, то её в результатах не будет
// полученный map содержит только ошибки
func (c Checker) check(las *Las) CheckResults {
res := make(CheckResults, 0)
res := make(CheckResults)
// key - имя проверки
// chk - сам проверщик
for key, chk := range c {
@ -111,15 +101,6 @@ func (c Checker) check(las *Las) CheckResults {
return res
}
/*
// NewDeptChecker - creation of a new checker to check the depth of monotony
func NewDeptChecker() Checker {
return Checker{
"DPTM": Check{"DPTM", "~A", "Dept step monotony", deptMonotony},
}
}
*/
// NewStdChecker - создание нового ПРОВЕРЩИКА las файла.
// WRAP = ON
// section ~Curve is empty
@ -164,17 +145,17 @@ func curvesIsEmpty(chk Check, las *Las) CheckRes {
}
func stepCheck(chk Check, las *Las) CheckRes {
return CheckRes{chk.name, TWarning{directOnRead, lasSecWellInfo, las.currentLine, fmt.Sprint("__WRN__ STEP parameter equal 0")}, nil, las.Step != 0.0}
return CheckRes{chk.name, TWarning{directOnRead, lasSecWellInfo, las.currentLine, fmt.Sprint("__WRN__ STEP parameter equal 0")}, nil, las.STEP() != 0.0}
}
func nullCheck(chk Check, las *Las) CheckRes {
return CheckRes{chk.name, TWarning{directOnRead, lasSecWellInfo, las.currentLine, fmt.Sprint("__WRN__ NULL parameter equal 0")}, nil, las.Null != 0.0}
return CheckRes{chk.name, TWarning{directOnRead, lasSecWellInfo, las.currentLine, fmt.Sprint("__WRN__ NULL parameter equal 0")}, nil, las.NULL() != 0.0}
}
func strtStop(chk Check, las *Las) CheckRes {
return CheckRes{chk.name, TWarning{directOnRead, lasSecWellInfo, las.currentLine, fmt.Sprintf("__WRN__ STRT: %4.3f == STOP: %4.3f", las.Strt, las.Stop)}, nil, las.Strt != las.Stop}
return CheckRes{chk.name, TWarning{directOnRead, lasSecWellInfo, las.currentLine, fmt.Sprintf("__WRN__ STRT: %4.3f == STOP: %4.3f", las.STRT(), las.STOP())}, nil, las.STRT() != las.STOP()}
}
func wellIsEmpty(chk Check, las *Las) CheckRes {
return CheckRes{chk.name, TWarning{directOnRead, lasSecWellInfo, las.currentLine, fmt.Sprintf("__WRN__ WELL: '%s' is empty", las.Well)}, nil, len(las.Well) != 0}
return CheckRes{chk.name, TWarning{directOnRead, lasSecWellInfo, las.currentLine, fmt.Sprintf("__WRN__ WELL: '%s' is empty", las.WELL())}, nil, len(las.WELL()) != 0}
}

Просмотреть файл

@ -24,16 +24,15 @@ type tLoadHeader struct {
}
var dLoadHeader = []tLoadHeader{
{fp.Join("data/more_20_warnings.las"), 1.2, "NO", 0.0, 0.0, 1.0, -32768.0, "6"}, // in file STEP=0.0 but this incorrect, Open() must replace STEP to actual from data
{fp.Join("data/expand_points_01.las"), 1.2, "NO", 1.0, 1.0, 0.1, -9999.00, "12-Сплошная"},
{fp.Join("data/2.0/cp1251_2.0_well_name.las"), 2.0, "NO", 0.0, 39.9, 0.3, -999.25, "Примерная-1 / бис(ё)"},
{fp.Join("data/2.0/cp1251_2.0_based.las"), 2.0, "NO", 0.0, 39.9, 0.3, -999.25, "Примерная-1/бис(ё)"},
{fp.Join("data/expand_points_01.las"), 1.2, "NO", 1.0, 1.0, 0.1, -9999.00, "12-Сплошная"},
{fp.Join("data/expand_points_01.las"), 1.2, "NO", 1.0, 1.0, 0.1, -9999.0, "12-Сплошная"},
{fp.Join("data/1.2/sample.las"), 1.2, "NO", 1670.0, 1660.0, -0.1250, -999.2500, "ANY ET AL OIL WELL #12"},
{fp.Join("data/2.0/sample_2.0.las"), 2.0, "NO", 1670.0, 1660.0, -0.1250, -999.2500, "AAAAA_2"},
{fp.Join("data/broken_parameter.las"), 2.0, "NO", 0.0, 39.9, 0.3, -999.25, "Примерная-1 / бис(ё)"}, // file contain error on STRT
{fp.Join("data/broken_header.las"), 2.0, "NO", 0.0, 39.9, 0.3, -999.25, "Примерная-1 / бис(ё)"}, // file contain only part of header
{fp.Join("data/more_20_warnings.las"), 1.2, "NO", 0.0, 0.0, 0.0, -32768.0, "6"}, // TODO STEP=0.0 but this incorrect, LoadHeader must replace STEP to actual from data
{fp.Join("data/duplicate_step.las"), 1.2, "NO", 1670.0, 1660.0, -0.1200, -999.2500, "ANY ET AL OIL WELL #12"}, // duplicate_step.las contains two line with STEP:: STEP.M -0.1250: STEP.M -0.1200: using LAST parameter
{fp.Join("data/duplicate_step.las"), 1.2, "NO", 1670.0, 1660.0, -0.1250, -999.2111, "ANY ET AL OIL WELL #12"}, // duplicate_step.las contains two line with STEP:: STEP.M -0.1250: STEP.M -0.1200: using LAST parameter
{fp.Join("data/encodings_utf8.las"), 1.2, "NO", 1670.0, 1660.0, -0.1250, -999.2500, "Скв #12Ω"}, // well name contain unicode char
{fp.Join("test_files/warning-test-files/01-STOP-02.las"), 2.0, "NO", 0.0, -999.2500, 0.1, -999.25, "Скв #12"}, // STOP not exist
}
@ -43,28 +42,41 @@ func TestLoadHeader(t *testing.T) {
for _, tmp := range dLoadHeader {
las = NewLas()
las.Open(tmp.fn)
las.LoadHeader()
assert.Equal(t, tmp.ver, las.Ver, fmt.Sprintf("<LoadHeader> file '%s' readed VER: %f, expected %f", las.FileName, las.Ver, tmp.ver))
assert.Equal(t, tmp.wrap, las.Wrap, fmt.Sprintf("<LoadHeader> file '%s' readed WRAP: %s, expected %s", las.FileName, las.Wrap, tmp.wrap))
assert.Equal(t, tmp.strt, las.Strt, fmt.Sprintf("<LoadHeader> file '%s' readed STRT: %f, expected %f", las.FileName, las.Strt, tmp.strt))
assert.Equal(t, tmp.stop, las.Stop, fmt.Sprintf("<LoadHeader> file '%s' readed STOP: %f, expected %f", las.FileName, las.Stop, tmp.stop))
assert.Equal(t, tmp.step, las.Step, fmt.Sprintf("<LoadHeader> file '%s' readed STEP: %f, expected %f", las.FileName, las.Step, tmp.step))
assert.Equal(t, tmp.null, las.Null, fmt.Sprintf("<LoadHeader> file '%s' readed NULL: %f, expected %f", las.FileName, las.Null, tmp.null))
assert.Equal(t, tmp.well, las.Well, fmt.Sprintf("<LoadHeader> file '%s' readed WELL: %s, expected %s", las.FileName, las.Well, tmp.well))
assert.Equal(t, tmp.ver, las.VERS(), fmt.Sprintf("<LoadHeader> file '%s' readed VER: %f, expected %f", las.FileName, las.VERS(), tmp.ver))
assert.Equal(t, tmp.wrap, las.WRAP(), fmt.Sprintf("<LoadHeader> file '%s' readed WRAP: %s, expected %s", las.FileName, las.WRAP(), tmp.wrap))
assert.Equal(t, tmp.null, las.NULL(), fmt.Sprintf("<LoadHeader> file '%s' readed NULL: %f, expected %f", las.FileName, las.NULL(), tmp.null))
assert.Equal(t, tmp.strt, las.STRT(), fmt.Sprintf("<LoadHeader> file '%s' readed STRT: %f, expected %f", las.FileName, las.STRT(), tmp.strt))
assert.Equal(t, tmp.stop, las.STOP(), fmt.Sprintf("<LoadHeader> file '%s' readed STOP: %f, expected %f", las.FileName, las.STOP(), tmp.stop))
assert.Equal(t, tmp.step, las.STEP(), fmt.Sprintf("<LoadHeader> file '%s' readed STEP: %f, expected %f", las.FileName, las.STEP(), tmp.step))
assert.Equal(t, tmp.well, las.WELL(), fmt.Sprintf("<LoadHeader> file '%s' readed WELL: %s, expected %s", las.FileName, las.WELL(), tmp.well))
}
}
var dLoadLasHeader = []tLoadHeader{
{fp.Join("data/expand_points_01.las"), 1.2, "NO", 1.0, 1.0, 0.1, -9999.00, "12-Сплошная"},
{fp.Join("data/2.0/cp1251_2.0_well_name.las"), 2.0, "NO", 0.0, 39.9, 0.3, -999.25, "Примерная-1 / бис(ё)"},
{fp.Join("data/2.0/cp1251_2.0_based.las"), 2.0, "NO", 0.0, 39.9, 0.3, -999.25, "Примерная-1/бис(ё)"},
{fp.Join("data/1.2/sample.las"), 1.2, "NO", 1670.0, 1660.0, -0.1250, -999.2500, "ANY ET AL OIL WELL #12"},
{fp.Join("data/2.0/sample_2.0.las"), 2.0, "NO", 1670.0, 1660.0, -0.1250, -999.2500, "AAAAA_2"},
{fp.Join("data/broken_parameter.las"), 2.0, "NO", 0.0, 39.9, 0.3, -999.25, "Примерная-1 / бис(ё)"}, // file contain error on STRT
{fp.Join("data/broken_header.las"), 2.0, "NO", 0.0, 39.9, 0.3, -999.25, "Примерная-1 / бис(ё)"}, // file contain only part of header
{fp.Join("data/more_20_warnings.las"), 1.2, "NO", 0.0, 0.0, 0.0, -32768.0, "6"}, // TODO STEP=0.0 but this incorrect, LoadLasHeader do not any repairs
{fp.Join("data/duplicate_step.las"), 1.2, "NO", 1670.0, 1660.0, -0.1250, -999.2111, "ANY ET AL OIL WELL #12"}, // duplicate_step.las contains two line with STEP:: STEP.M -0.1250: STEP.M -0.1200: using LAST parameter
{fp.Join("data/encodings_utf8.las"), 1.2, "NO", 1670.0, 1660.0, -0.1250, -999.2500, "Скв #12Ω"}, // well name contain unicode char
{fp.Join("test_files/warning-test-files/01-STOP-02.las"), 2.0, "NO", 0.0, -999.2500, 0.1, -999.25, "Скв #12"}, // STOP not exist
}
func TestLoadLasHeader(t *testing.T) {
for _, tmp := range dLoadHeader {
for _, tmp := range dLoadLasHeader {
las, err := LoadLasHeader(tmp.fn)
assert.Nil(t, err)
assert.Equal(t, tmp.ver, las.Ver, fmt.Sprintf("<LoadHeader> file '%s' readed VER: %f, expected %f", las.FileName, las.Ver, tmp.ver))
assert.Equal(t, tmp.wrap, las.Wrap, fmt.Sprintf("<LoadHeader> file '%s' readed WRAP: %s, expected %s", las.FileName, las.Wrap, tmp.wrap))
assert.Equal(t, tmp.strt, las.Strt, fmt.Sprintf("<LoadHeader> file '%s' readed STRT: %f, expected %f", las.FileName, las.Strt, tmp.strt))
assert.Equal(t, tmp.stop, las.Stop, fmt.Sprintf("<LoadHeader> file '%s' readed STOP: %f, expected %f", las.FileName, las.Stop, tmp.stop))
assert.Equal(t, tmp.step, las.Step, fmt.Sprintf("<LoadHeader> file '%s' readed STEP: %f, expected %f", las.FileName, las.Step, tmp.step))
assert.Equal(t, tmp.null, las.Null, fmt.Sprintf("<LoadHeader> file '%s' readed NULL: %f, expected %f", las.FileName, las.Null, tmp.null))
assert.Equal(t, tmp.well, las.Well, fmt.Sprintf("<LoadHeader> file '%s' readed WELL: %s, expected %s", las.FileName, las.Well, tmp.well))
assert.Equal(t, tmp.ver, las.VERS(), fmt.Sprintf("<LoadHeader> file '%s' readed VER: %f, expected %f", las.FileName, las.VERS(), tmp.ver))
assert.Equal(t, tmp.wrap, las.WRAP(), fmt.Sprintf("<LoadHeader> file '%s' readed WRAP: %s, expected %s", las.FileName, las.WRAP(), tmp.wrap))
assert.Equal(t, tmp.strt, las.STRT(), fmt.Sprintf("<LoadHeader> file '%s' readed STRT: %f, expected %f", las.FileName, las.STRT(), tmp.strt))
assert.Equal(t, tmp.stop, las.STOP(), fmt.Sprintf("<LoadHeader> file '%s' readed STOP: %f, expected %f", las.FileName, las.STOP(), tmp.stop))
assert.Equal(t, tmp.step, las.STEP(), fmt.Sprintf("<LoadHeader> file '%s' readed STEP: %f, expected %f", las.FileName, las.STEP(), tmp.step))
assert.Equal(t, tmp.null, las.NULL(), fmt.Sprintf("<LoadHeader> file '%s' readed NULL: %f, expected %f", las.FileName, las.NULL(), tmp.null))
assert.Equal(t, tmp.well, las.WELL(), fmt.Sprintf("<LoadHeader> file '%s' readed WELL: %s, expected %s", las.FileName, las.WELL(), tmp.well))
}
//test error case
las, err := LoadLasHeader("not_exist_file.las") //file not exist

Просмотреть файл

@ -30,6 +30,7 @@ type HeaderParam struct {
// HeaderSection - contain parameters of Well section
type HeaderSection struct {
name rune
params map[string]HeaderParam
parse ParseHeaderParam // function for parse one line
}
@ -43,13 +44,16 @@ func (hs HeaderSection) uniqueName(name string) string {
}
// ParseHeaderParam - function to parse one line of header
// return new of added parameter and warning
// return new of added parameter and warning
// on success TWarning.Empty() == true
// s - string readed from source file
// i - number of line in source file
type ParseHeaderParam func(s string, i int) (HeaderParam, TWarning)
// NewVerSection - create section ~V
func NewVerSection() HeaderSection {
sec := HeaderSection{}
sec.name = 'V'
sec.params = make(map[string]HeaderParam)
sec.parse = defParse
return sec
@ -64,6 +68,7 @@ func defParse(s string, i int) (HeaderParam, TWarning) {
// NewOthSection - create section ~W
func NewOthSection() HeaderSection {
sec := HeaderSection{}
sec.name = 'O'
sec.params = make(map[string]HeaderParam)
sec.parse = defParse
return sec
@ -72,6 +77,7 @@ func NewOthSection() HeaderSection {
// NewParSection - create section ~W
func NewParSection() HeaderSection {
sec := HeaderSection{}
sec.name = 'P'
sec.params = make(map[string]HeaderParam)
sec.parse = defParse
return sec
@ -80,6 +86,7 @@ func NewParSection() HeaderSection {
// NewCurSection - create section ~C
func NewCurSection() HeaderSection {
sec := HeaderSection{}
sec.name = 'C'
sec.params = make(map[string]HeaderParam)
sec.parse = curParse // parser for section ~C
return sec
@ -94,6 +101,7 @@ func curParse(s string, i int) (HeaderParam, TWarning) {
// NewWelSection - create section ~W
func NewWelSection() HeaderSection {
sec := HeaderSection{}
sec.name = 'W'
sec.params = make(map[string]HeaderParam)
sec.parse = welParse20 // by default using 2.0 version parser
return sec
@ -140,16 +148,6 @@ func (p *HeaderParam) wellName20() {
p.Unit = ""
}
func wellNameFromParam(p *HeaderParam) string {
if len(p.Unit) == 0 {
return p.Val
}
if len(p.Val) == 0 {
return p.Unit //TODO не тестируется
}
return p.Unit + " " + p.Val
}
//PrepareParamStr - prepare string to parse, replace many space to one, replace tab to space, replace combination of separator to one
func PrepareParamStr(s string) string {
s = strings.ReplaceAll(s, "\t", " ")
@ -158,6 +156,24 @@ func PrepareParamStr(s string) string {
return strings.TrimSpace(s)
}
// NewHeaderParam - create new object LasParam
// STRT. m 10.0 : start
// field[0] field[1] field[2] field[3]
func NewHeaderParam(s string, i int) *HeaderParam {
par := new(HeaderParam)
par.lineNo = i
paramFields := ParseParamStr(s)
par.Name = paramFields[0]
par.Unit = paramFields[1]
par.Val = paramFields[2]
if (len(par.Val) == 0) && (len(par.Unit) > 0) {
par.Val = par.Unit
par.Unit = ""
}
par.Desc = paramFields[3]
return par
}
// ParseParamStr - parse string from las file
// return slice with 4 string and error if occure
// before process input string 2 or more space replace on 1 space
@ -198,6 +214,19 @@ func ParseParamStr(s string) (f [4]string) {
return
}
// NewCurveHeaderParam - create new object LasParam
// STRT. m 10.0 : start
// field[0] field[1] field[2] field[3]
func NewCurveHeaderParam(s string, i int) *HeaderParam {
par := new(HeaderParam)
par.lineNo = i
paramFields := ParseCurveStr(s)
par.Name = paramFields[0]
par.Unit = paramFields[1]
par.Desc = paramFields[2]
return par
}
const defCurveName = "-EL-" // curve name for null input
// ParseCurveStr - parse input string to 3 separated string
@ -235,37 +264,6 @@ func ParseCurveStr(s string) (f [3]string) {
return
}
// NewHeaderParam - create new object LasParam
// STRT. m 10.0 : start
// field[0] field[1] field[2] field[3]
func NewHeaderParam(s string, i int) *HeaderParam {
par := new(HeaderParam)
par.lineNo = i
paramFields := ParseParamStr(s)
par.Name = paramFields[0]
par.Unit = paramFields[1]
par.Val = paramFields[2]
if (len(par.Val) == 0) && (len(par.Unit) > 0) {
par.Val = par.Unit
par.Unit = ""
}
par.Desc = paramFields[3]
return par
}
// NewCurveHeaderParam - create new object LasParam
// STRT. m 10.0 : start
// field[0] field[1] field[2] field[3]
func NewCurveHeaderParam(s string, i int) *HeaderParam {
par := new(HeaderParam)
par.lineNo = i
paramFields := ParseCurveStr(s)
par.Name = paramFields[0]
par.Unit = paramFields[1]
par.Desc = paramFields[2]
return par
}
//LasCurve - class to store one log in Las
type LasCurve struct {
HeaderParam
@ -357,7 +355,7 @@ func (curves LasCurves) UniqueName(curveName string) string {
// количество кривых в контейнере
// два хеша от строк с именами всех кривых
func (curves LasCurves) Cmp(otheCurves LasCurves) (res bool) {
res = (len(curves) == len(curves))
res = (len(curves) == len(otheCurves))
if res {
curvesName := make([]string, 0, len(curves))
for _, k := range curves {

Просмотреть файл

@ -37,8 +37,10 @@ var dReadWellParamStep = []tReadWellParamStep{
func TestReadWellParam(t *testing.T) {
las := NewLas()
for i, tmp := range dReadWellParamStep {
las.ReadWellParam(tmp.s)
assert.Equal(t, tmp.v, las.Step, fmt.Sprintf("<ReadWellParam> on test %d return STEP: '%f' expect: '%f'\n", i, las.Step, tmp.v))
//las.ReadWellParam(tmp.s)
hp, _ := las.WelSec.parse(tmp.s, 0)
las.WelSec.params["STEP"] = hp
assert.Equal(t, tmp.v, las.STEP(), fmt.Sprintf("<ReadWellParam> on test %d return STEP: '%f' expect: '%f'\n", i, las.STEP(), tmp.v))
}
}

Просмотреть файл

@ -32,10 +32,10 @@ var dSummaryCheck = []tSummaryCheck{
{fp.Join("data/1001178549.las"), 2.0, "YES", 1783.5, 1784.5, 0.25, -999.25, "1-28", 27, 0, true},
{fp.Join("data/alog.las"), 1.20, "NO", 0, 0, 0.05, -999.25, "", 9, 24, false},
{fp.Join("data/autodepthindex_F.las"), 1.20, "NO", 0, 100, 1, -999.25, "ANY ET AL OIL WELL #12", 2, 101, false},
{fp.Join("data/barebones2.las"), 2.0, "NO", -999.25, -999.25, -999.25, 0, "", 0, 0, true}, // step и null не правятся, отсутствует секция Curve, ошибка заголовка
{fp.Join("data/barebones2.las"), 2.0, "NO", -999.25, -999.25, -999.25, -999.25, "", 0, 0, true}, // step и null не правятся, отсутствует секция Curve, ошибка заголовка
{fp.Join("data/blank_line.las"), 2.0, "NO", -999.25, -999.25, 0.0833333333333333, -999.25, "", 1, 0, true},
{fp.Join("data/data_characters.las"), 2.0, "NO", 0, 0, 10, -999.25, "", 4, 0, true},
{fp.Join("data/duplicate_step.las"), 1.2, "NO", 1670, 1660, -0.12, -999.25, "ANY ET AL OIL WELL #12", 8, 3, false},
{fp.Join("data/duplicate_step.las"), 1.2, "NO", 1670, 1660, -0.125, -999.2111, "ANY ET AL OIL WELL #12", 8, 3, false},
{fp.Join("data/encodings_utf8.las"), 1.2, "NO", 1670, 1660, -0.125, -999.25, "Скв #12Ω", 8, 3, false},
{fp.Join("data/encodings_utf8_20.las"), 2.0, "NO", 1670, 1660, -0.125, -999.25, "Скв #12Ω", 8, 3, false},
{fp.Join("data/encodings_utf8wbom.las"), 1.2, "NO", 1670, 1660, -0.125, -999.25, "Скважина #12Ω", 8, 3, false},
@ -63,16 +63,19 @@ func TestSummaryRead(t *testing.T) {
las := NewLas()
n, _ := las.Open(tmp.fn)
assert.Equal(t, tmp.nums, n, fmt.Sprintf("<TestSummaryRead> nums fail on file: '%s'\n", tmp.fn))
assert.Equal(t, tmp.ver, las.VERS(), fmt.Sprintf("<TestSummaryRead> ver fail on file: '%s'\n", tmp.fn))
assert.Equal(t, tmp.wrap, las.WRAP(), fmt.Sprintf("<TestSummaryRead> wrap fail on file: '%s'\n", tmp.fn))
assert.Equal(t, tmp.strt, las.STRT(), fmt.Sprintf("<TestSummaryRead> strt fail on file: '%s'\n", tmp.fn))
assert.Equal(t, tmp.stop, las.STOP(), fmt.Sprintf("<TestSummaryRead> stop fail on file: '%s'\n", tmp.fn))
assert.Equal(t, tmp.step, las.STEP(), fmt.Sprintf("<TestSummaryRead> step fail on file: '%s'\n", tmp.fn))
assert.Equal(t, tmp.null, las.NULL(), fmt.Sprintf("<TestSummaryRead> null fail on file: '%s'\n", tmp.fn))
assert.Equal(t, tmp.well, las.WELL(), fmt.Sprintf("<TestSummaryRead> null fail on file: '%s'\n", tmp.fn))
//две проверки касающиеся секции кривых
//кривые попадают в два контейнера: las.Logs и las.CurSec.params
assert.Equal(t, tmp.curv, len(las.Logs), fmt.Sprintf("<TestSummaryRead> curves fail on file: '%s'\n", tmp.fn))
assert.Equal(t, tmp.curv, len(las.CurSec.params), fmt.Sprintf("<TestSummaryRead> curves fail on file: '%s'\n", tmp.fn))
assert.Equal(t, tmp.ver, las.Ver, fmt.Sprintf("<TestSummaryRead> ver fail on file: '%s'\n", tmp.fn))
assert.Equal(t, tmp.ver, las.VERS(), fmt.Sprintf("<TestSummaryRead> ver fail on file: '%s'\n", tmp.fn))
assert.Equal(t, tmp.wrap, las.Wrap, fmt.Sprintf("<TestSummaryRead> wrap fail on file: '%s'\n", tmp.fn))
assert.Equal(t, tmp.strt, las.Strt, fmt.Sprintf("<TestSummaryRead> strt fail on file: '%s'\n", tmp.fn))
assert.Equal(t, tmp.stop, las.Stop, fmt.Sprintf("<TestSummaryRead> stop fail on file: '%s'\n", tmp.fn))
assert.Equal(t, tmp.step, las.Step, fmt.Sprintf("<TestSummaryRead> step fail on file: '%s'\n", tmp.fn))
assert.Equal(t, tmp.null, las.Null, fmt.Sprintf("<TestSummaryRead> null fail on file: '%s'\n", tmp.fn))
assert.Equal(t, tmp.well, las.Well)
//проверки по данным
//if tmp.nums
}
}
@ -116,11 +119,13 @@ func TestLasCheck(t *testing.T) {
s = lasLog.msgCurve.String(fp.Join("data/test-curve-sec-empty-mnemonic+.las"))
assert.Contains(t, s, "test-curve-sec-empty-mnemonic+.las'##")
// проверка на возврат nil
// проверка на возврат nil при невозможности выполнить проверку
lasLog, err := LasDeepCheck(fp.Join("data/test-curve-sec-empty-mnemonic+.las"), fp.Join("data/mnemonic.-"), fp.Join("data/dic.ini"))
assert.Nil(t, lasLog)
assert.NotNil(t, err)
lasLog, err = LasDeepCheck(fp.Join("data/test-curve-sec-empty-mnemonic+.las"), fp.Join("data/mnemonic.ini"), fp.Join("data/dic.-"))
assert.Nil(t, lasLog)
assert.NotNil(t, err)
lasLog, err = LasDeepCheck(fp.Join("data/test-curve-sec-empty-mnemonic+.las"), fp.Join("data/mnemonic.ini"), fp.Join("data/dic.ini"))
assert.Nil(t, err)
@ -152,6 +157,7 @@ func TestLasCheck(t *testing.T) {
// случай если файла нет "data/-.las"
lasLog, err = LasDeepCheck(fp.Join("data/-.las"), fp.Join("data/mnemonic.ini"), fp.Join("data/dic.ini"))
assert.NotNil(t, lasLog)
assert.NotNil(t, err)
assert.NotNil(t, lasLog.errorOnOpen)
// случай если las файл WRAP

Просмотреть файл

@ -103,7 +103,7 @@ func TestGetStrtFromData(t *testing.T) {
for _, tmp := range dGetDataStrt {
las := NewLas()
las.Open(tmp.fn)
assert.Equal(t, tmp.st, las.Strt, fmt.Sprintf("<TestGetStepFromData> fail on file '%s' \n", tmp.fn))
assert.Equal(t, tmp.st, las.STRT(), fmt.Sprintf("<TestGetStrtFromData> fail on file '%s' \n", tmp.fn))
}
}
@ -123,24 +123,24 @@ func TestGetStepFromData(t *testing.T) {
for _, tmp := range dGetDataStep {
las := NewLas()
las.Open(tmp.fn)
assert.Equal(t, tmp.st, las.Step, fmt.Sprintf("<TestGetStepFromData> fail on file '%s' \n", tmp.fn))
assert.Equal(t, tmp.st, las.STEP(), fmt.Sprintf("<TestGetStepFromData> fail on file '%s' \n", tmp.fn))
}
}
func TestLasSetNull(t *testing.T) {
las := NewLas()
las.Open(fp.Join("data/expand_points_01.las"))
assert.Equal(t, -9999.00, las.Null)
assert.Equal(t, -9999.00, las.NULL())
las.SetNull(-999.25)
assert.Equal(t, -999.25, las.Null)
assert.Equal(t, -999.25, las.NULL())
las.Save("-tmp.las")
las = NewLas()
las.Open("-tmp.las")
assert.Equal(t, -999.25, las.Null)
assert.Equal(t, -999.25, las.NULL())
log := las.Logs[1]
assert.Equal(t, las.Null, log.V[2])
assert.Equal(t, las.Null, las.Logs[2].V[6])
assert.Equal(t, las.NULL(), log.V[2])
assert.Equal(t, las.NULL(), las.Logs[2].V[6])
err := os.Remove("-tmp.las")
assert.Nil(t, err, fmt.Sprintf("%v", err))
}
@ -179,11 +179,11 @@ func TestLasSave(t *testing.T) {
//os.Remove(tmp.fn)
assert.Nil(t, err)
assert.Equal(t, 5, n)
assert.Equal(t, tmp.newNull, las.Null)
assert.Equal(t, tmp.strt, las.Strt)
assert.Equal(t, tmp.stop, las.Stop)
assert.Equal(t, tmp.step, las.Step)
assert.Equal(t, tmp.well, las.Well)
assert.Equal(t, tmp.newNull, las.NULL())
assert.Equal(t, tmp.strt, las.STRT())
assert.Equal(t, tmp.stop, las.STOP())
assert.Equal(t, tmp.step, las.STEP())
assert.Equal(t, tmp.well, las.WELL())
assert.Equal(t, "DEPT", las.Logs[0].Name)
assert.Equal(t, 1.1, las.Logs[0].D[1])
assert.Equal(t, 1.0, las.Logs[0].V[0])
@ -195,7 +195,7 @@ func TestLasSave(t *testing.T) {
func TestSetNullOnEmptyLas(t *testing.T) {
las := NewLas()
las.SetNull(-1000)
assert.Equal(t, -1000.0, las.Null)
assert.Equal(t, -1000.0, las.NULL())
}
func TestLasIsEmpty(t *testing.T) {

Просмотреть файл

@ -6,6 +6,7 @@ import (
"fmt"
"os"
fp "path/filepath"
"strconv"
"github.com/softlandia/cpd"
)
@ -21,10 +22,10 @@ func isIgnoredLine(s string) bool {
// два las равны если равны их основные параметры: STRT, STOP, STEP, NULL, количество точек в данных,
// а также количество кривых и совпадают имена кривых
func cmpLas(correct, las *Las) (res bool) {
res = (correct.Strt == las.Strt)
res = res && (correct.Stop == las.Stop)
res = res && (correct.Step == las.Step)
res = res && (correct.Null == las.Null)
res = (correct.STRT() == las.STRT())
res = res && (correct.STOP() == las.STOP())
res = res && (correct.STEP() == las.STEP())
res = res && (correct.NULL() == las.NULL())
res = res && (correct.NumPoints() == las.NumPoints())
res = res && correct.Logs.Cmp(las.Logs)
return res
@ -53,11 +54,13 @@ func makeSampleLas(
} else {
las = NewLas(cp)
}
las.Null = null
las.Strt = strt
las.Stop = stop
las.Step = step
las.Well = well
las.VerSec.params["VERS"] = HeaderParam{"2.0", "VERS", "", "", "", "glasio (c) softlandia@gmail.com", 2}
las.VerSec.params["WRAP"] = HeaderParam{"NO", "WRAP", "", "", "", "one line per depth step", 3}
las.WelSec.params["NULL"] = HeaderParam{strconv.FormatFloat(null, 'f', -1, 64), "NULL", "", "", "", "null value", 5}
las.WelSec.params["STRT"] = HeaderParam{strconv.FormatFloat(strt, 'f', -1, 64), "STRT", "", "", "", "first index value", 6}
las.WelSec.params["STOP"] = HeaderParam{strconv.FormatFloat(stop, 'f', -1, 64), "STOP", "", "", "", "last index value", 7}
las.WelSec.params["STEP"] = HeaderParam{strconv.FormatFloat(step, 'f', -1, 64), "STEP", "", "", "", "step of index", 8}
las.WelSec.params["WELL"] = HeaderParam{well, "WELL", "", "", "", "well", 9}
curve := NewLasCurve("DEPT.m :", las)
curve.D = append(curve.D, 1.0, 1.1, 1.2, 1.3, 1.4)
@ -71,6 +74,8 @@ func makeSampleLas(
}
// LoadLasHeader - utility function, if need read only header without data
// read header as is
// not repaire any parameters: step, stop, etc...
func LoadLasHeader(fileName string) (*Las, error) {
las := NewLas()
iFile, err := os.Open(fileName)
@ -85,7 +90,6 @@ func LoadLasHeader(fileName string) (*Las, error) {
if err != nil {
return nil, err
}
//las.ePoints = las.ReadRows()
las.ReadRows()
las.LoadHeader()
return las, nil

Просмотреть файл

@ -9,8 +9,6 @@ import (
)
const (
//defWarningCount = 10
//warningUNDEF = 0
directOnRead = 1
directOnWrite = 2
)

Просмотреть файл

@ -0,0 +1,97 @@
las.go:679:21: Error return value of `writer.WriteString` is not checked (errcheck)
writer.WriteString(w.String())
^
las.go:680:21: Error return value of `writer.WriteString` is not checked (errcheck)
writer.WriteString("\n")
^
las.go:693:19: Error return value of `oFile.WriteString` is not checked (errcheck)
oFile.WriteString("**file: " + las.FileName + "**\n")
^
las.go:695:19: Error return value of `oFile.WriteString` is not checked (errcheck)
oFile.WriteString("\n")
^
las_header_test.go:44:11: Error return value of `las.Open` is not checked (errcheck)
las.Open(tmp.fn)
^
las_logger.go:50:16: Error return value of `f.WriteString` is not checked (errcheck)
f.WriteString(msg)
^
las_logger.go:82:16: Error return value of `f.WriteString` is not checked (errcheck)
f.WriteString(s)
^
las_logger.go:84:15: Error return value of `f.WriteString` is not checked (errcheck)
f.WriteString("\n")
^
las_test.go:50:10: Error return value of `las.Open` is not checked (errcheck)
las.Open(fp.Join("data/more_20_warnings.las"))
^
las_test.go:57:10: Error return value of `las.Open` is not checked (errcheck)
las.Open(fp.Join("data/more_20_warnings.las"))
^
las_test.go:62:17: Error return value of `las.SaveWarning` is not checked (errcheck)
las.SaveWarning(fp.Join("data/more_20_warnings.wrn"))
^
las_test.go:136:10: Error return value of `las.Save` is not checked (errcheck)
las.Save("-tmp.las")
^
las_test.go:277:11: Error return value of `las.Save` is not checked (errcheck)
las.Save(tmp.fn)
^
las_util.go:94:16: Error return value of `las.LoadHeader` is not checked (errcheck)
las.LoadHeader()
^
las_constants.go:13:2: `_LasMnemonicFormat` is unused (deadcode)
_LasMnemonicFormat = "#MNEM.UNIT DATA :DESCRIPTION\n"
^
las_constants.go:18:2: `_LasRkb` is unused (deadcode)
_LasRkb = " RKB.M %8.3f :KB or GL\n"
^
las_constants.go:19:2: `_LasXcoord` is unused (deadcode)
_LasXcoord = " XWELL.M %8.3f :Well head X coordinate\n"
^
las_constants.go:20:2: `_LasYcoord` is unused (deadcode)
_LasYcoord = " YWELL.M %8.3f :Well head Y coordinate\n"
^
las_constants.go:21:2: `_LasOilComp` is unused (deadcode)
_LasOilComp = " COMP. %-43.43s:OIL COMPANY\n"
^
las_constants.go:23:2: `_LasField` is unused (deadcode)
_LasField = " FLD . %-43.43s:FIELD\n"
^
las_constants.go:24:2: `_LasLoc` is unused (deadcode)
_LasLoc = " LOC . %-43.43s:LOCATION\n"
^
las_constants.go:25:2: `_LasCountry` is unused (deadcode)
_LasCountry = " CTRY. %-43.43s:COUNTRY\n"
^
las_constants.go:26:2: `_LasServiceComp` is unused (deadcode)
_LasServiceComp = " SRVC. %-43.43s:SERVICE COMPANY\n"
^
las_constants.go:27:2: `_LasDate` is unused (deadcode)
_LasDate = " DATE. %-43.43s:DATE\n"
^
las_constants.go:28:2: `_LasAPI` is unused (deadcode)
_LasAPI = " API . %-43.43s:API NUMBER\n"
^
las_constants.go:29:2: `_LasUwi` is unused (deadcode)
_LasUwi = " UWI . %-43.43s:UNIVERSAL WELL INDEX\n"
^
las_constants.go:31:2: `_LasCurvFormat` is unused (deadcode)
_LasCurvFormat = "#MNEM.UNIT :DESCRIPTION\n"
^
las_warning.go:13:2: `directOnWrite` is unused (deadcode)
directOnWrite = 2
^
las_summary_test.go:25:2: `werr` is unused (structcheck)
werr bool //не используется
^
las_test.go:73:5: ineffectual assignment to `err` (ineffassign)
f, err := os.Create(fp.Join("data/w1_more_20_warnings.txt"))
^
las_checker.go:102:28: S1019: should use make(CheckResults) instead (gosimple)
res := make(CheckResults, 0)
^
las_logger.go:102:23: func `(*tMMnemonic).save` is unused (unused)
las_checker.go:74:25: func `CheckResults.isFatal` is unused (unused)
las_logger.go:48:21: func `(*tCheckMsg).save` is unused (unused)
las_logger.go:79:22: func `(*tCurvRprt).save` is unused (unused)

Просмотреть файл

@ -1 +1 @@
0.2.3
0.2.4