This commit is contained in:
softlandia 2020-04-28 23:04:01 +04:00
Родитель b0000b80c7
Коммит 775d60b031
16 изменённых файлов: 713 добавлений и 283 удалений

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

@ -1,4 +1,8 @@
## ver 0.1.6 // 2020.04.13 ## ## ver 0.1.7 // 2020.04.28 ##
- внедрена первая версия модуля Checker, пока на слайсах, ожидается переделка на map
## ver 0.1.6 // 2020.04.13 ##
- мелкие улучшения - мелкие улучшения

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

@ -86,6 +86,8 @@ Kavernomer= CALI
КАВ-9_10 = CALI КАВ-9_10 = CALI
КАВ26 = CALI КАВ26 = CALI
КАВ268 = CALI КАВ268 = CALI
CAL = CALI
CALvh = CALI
DN = BIN DN = BIN
DN_ = BIN DN_ = BIN
@ -94,6 +96,7 @@ Dnom = BIN
ДСн = BIN ДСн = BIN
ДСном = BIN ДСном = BIN
Дн = BIN Дн = BIN
CAL_nom = BIN
ДТП = DTP ДТП = DTP
= DTP = DTP
@ -211,6 +214,7 @@ A1M0 = GZ2
A125M01N= GZ2 A125M01N= GZ2
À2Ì05N = GZ2 À2Ì05N = GZ2
GZ = GZ3
A2* = GZ3 A2* = GZ3
A2*_O = GZ3 A2*_O = GZ3
A2*_O_O = GZ3 A2*_O_O = GZ3
@ -361,6 +365,7 @@ IK Omm = 6F1I
IKOmm = 6F1I IKOmm = 6F1I
ИКомм = 6F1I ИКомм = 6F1I
ИКомм24 = 6F1I ИКомм24 = 6F1I
RILD = 6F1I
BK = LL3 BK = LL3
BK14 = LL3 BK14 = LL3
@ -383,6 +388,7 @@ BK_Р = LL3
ВК_Р = LL3 ВК_Р = LL3
бк = LL3 бк = LL3
LLD = LL3 LLD = LL3
LL8 = LL3
MBK = MLL MBK = MLL
BMK = MLL BMK = MLL
@ -543,6 +549,8 @@ GGP_Р = RHOB
ГГКПсем = RHOB ГГКПсем = RHOB
ГГКР = RHOB ГГКР = RHOB
ПЛ_ГГ = RHOB ПЛ_ГГ = RHOB
DEN = RHOB
DENkz = RHOB
GGK-bz = GGKbz GGK-bz = GGKbz
ГГКбз = GGKbz ГГКбз = GGKbz
@ -571,5 +579,6 @@ Rez = RM
ннкбз = RFEN ннкбз = RFEN
ннкмз = RNEN ннкмз = RNEN
Кгл = VCL Кгл = VCL
КП = POR КП = POR
So = SOIL

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

@ -36,3 +36,9 @@ GGKmz = ГГКп бз
OGZ = ГЗ обр OGZ = ГЗ обр
RFEN = ННК бз RFEN = ННК бз
RNEN = ННК мз RNEN = ННК мз
COLL = Признак коллектора
ZONELOG = номер пласта
POR = пористость
SOIL = насыщенность
VCL = глинистость
SAT = признак насыщения

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

@ -1,46 +1,42 @@
**file: data\more_20_warnings.las** **file: data\more_20_warnings.las**
0, line: -1, desc: STEP parameter equal 0, replace to 0.000 0, line: -1, desc: STEP parameter equal 0, replace to 0.000
1, line: -1, desc: invalid STRT: 0.000 or STOP: 0.000, will be replace to actually 1, line: 24, desc: can't convert string: '6.2.2' to number, set to NULL
2, line: 24, desc: can't convert string: '6.2.2' to number, set to NULL 2, line: 25, desc: not all column readed, set log value to NULL
3, line: 25, desc: not all column readed, set log value to NULL 3, line: 25, desc: not all column readed, set log value to NULL
4, line: 25, desc: not all column readed, set log value to NULL 4, line: 26, desc: actual number of data lines more than expected, check: STRT, STOP, STEP
5, line: 27, desc: actual step 1.00 ≠ global STEP 0.00 5, line: 26, desc: expand number of points
6, line: 27, desc: can't convert string: '6.2.2' to number, set to NULL 6, line: 27, desc: can't convert string: '6.2.2' to number, set to NULL
7, line: 29, desc: actual step 1.00 ≠ global STEP 0.00 7, line: 29, desc: can't convert string: '5.97.' to number, set to NULL
8, line: 29, desc: can't convert string: '5.97.' to number, set to NULL 8, line: 30, desc: actual number of data lines more than expected, check: STRT, STOP, STEP
9, line: 31, desc: actual step 1.00 ≠ global STEP 0.00 9, line: 30, desc: expand number of points
10, line: 31, desc: can't convert string: '6.47.' to number, set to NULL 10, line: 31, desc: can't convert string: '6.47.' to number, set to NULL
11, line: 33, desc: actual step 64.00 ≠ global STEP 0.00 11, line: 33, desc: actual step 64.00 ≠ global STEP 1.00
12, line: 33, desc: step 64.00 ≠ previously step 1.00 12, line: 33, desc: step 64.00 ≠ previously step 1.00
13, line: 33, desc: can't convert string: '5.97.' to number, set to NULL 13, line: 33, desc: can't convert string: '5.97.' to number, set to NULL
14, line: 35, desc: actual step 47.00 ≠ global STEP 0.00 14, line: 35, desc: actual step 47.00 ≠ global STEP 1.00
15, line: 35, desc: step 47.00 ≠ previously step 64.00 15, line: 35, desc: step 47.00 ≠ previously step 64.00
16, line: 35, desc: can't convert string: '5.47.' to number, set to NULL 16, line: 35, desc: can't convert string: '5.47.' to number, set to NULL
17, line: 37, desc: actual step 1.00 ≠ global STEP 0.00 17, line: 37, desc: step 1.00 ≠ previously step 47.00
18, line: 37, desc: step 1.00 ≠ previously step 47.00 18, line: 37, desc: can't convert string: '4.7.' to number, set to NULL
19, line: 37, desc: can't convert string: '4.7.' to number, set to NULL 19, line: 38, desc: actual number of data lines more than expected, check: STRT, STOP, STEP
20, line: 38, desc: actual step 1.00 ≠ global STEP 0.00 20, line: 38, desc: expand number of points
21, line: 38, desc: can't convert string: '4.7.' to number, set to NULL 21, line: 38, desc: can't convert string: '4.7.' to number, set to NULL
22, line: 40, desc: line: 40 is empty, ignore 22, line: 40, desc: line: 40 is empty, ignore
23, line: 41, desc: actual step -117.20 ≠ global STEP 0.00 23, line: 41, desc: actual step -117.20 ≠ global STEP 1.00
24, line: 41, desc: step -117.20 ≠ previously step 1.00 24, line: 41, desc: step -117.20 ≠ previously step 1.00
25, line: 41, desc: not all column readed, set log value to NULL 25, line: 41, desc: not all column readed, set log value to NULL
26, line: 42, desc: actual step 170.20 ≠ global STEP 0.00 26, line: 42, desc: actual step 170.20 ≠ global STEP 1.00
27, line: 42, desc: step 170.20 ≠ previously step -117.20 27, line: 42, desc: step 170.20 ≠ previously step -117.20
28, line: 43, desc: actual step 1.00 ≠ global STEP 0.00 28, line: 43, desc: step 1.00 ≠ previously step 170.20
29, line: 43, desc: step 1.00 ≠ previously step 170.20 29, line: 45, desc: actual step 4.00 ≠ global STEP 1.00
30, line: 44, desc: actual step 1.00 ≠ global STEP 0.00 30, line: 45, desc: step 4.00 ≠ previously step 1.00
31, line: 45, desc: actual step 4.00 ≠ global STEP 0.00 31, line: 46, desc: step 1.00 ≠ previously step 4.00
32, line: 45, desc: step 4.00 ≠ previously step 1.00 32, line: 49, desc: actual number of data lines more than expected, check: STRT, STOP, STEP
33, line: 46, desc: actual step 1.00 ≠ global STEP 0.00 33, line: 49, desc: expand number of points
34, line: 46, desc: step 1.00 ≠ previously step 4.00 34, line: 49, desc: actual step 3.00 ≠ global STEP 1.00
35, line: 48, desc: actual step 1.00 ≠ global STEP 0.00 35, line: 49, desc: step 3.00 ≠ previously step 1.00
36, line: 49, desc: actual step 3.00 ≠ global STEP 0.00 36, line: 50, desc: step 1.00 ≠ previously step 3.00
37, line: 49, desc: step 3.00 ≠ previously step 1.00 37, line: 54, desc: actual step 0.00 ≠ global STEP 1.00
38, line: 50, desc: actual step 1.00 ≠ global STEP 0.00 38, line: 54, desc: step 0.00 ≠ previously step 1.00
39, line: 50, desc: step 1.00 ≠ previously step 3.00 39, line: 55, desc: actual step 0.00 ≠ global STEP 1.00
40, line: 51, desc: actual step 1.00 ≠ global STEP 0.00
41, line: 52, desc: actual step 1.00 ≠ global STEP 0.00
42, line: 53, desc: actual step 1.00 ≠ global STEP 0.00
43, line: 54, desc: step 0.00 ≠ previously step 1.00

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

@ -18,7 +18,7 @@ UWI . WELL ID : 100091604920W300
D.M : 1 DEPTH D.M : 1 DEPTH
A.US/M : 2 SONIC TRANSIT TIME A.US/M : 2 SONIC TRANSIT TIME
B.K/M3 : 3 BULK DENSITY B.K/M3 : 3 BULK DENSITY
C.V/V : 4 NEUTRON POROSITY SP.V/V : 4 SP
-EL- . : -EL- . :
-EL-1.m : -EL-1.m :
-EL-2.v/v : -EL-2.v/v :

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

@ -18,7 +18,7 @@ UWI . WELL ID : 100091604920W300
D.M : 1 DEPTH D.M : 1 DEPTH
A.US/M : 2 SONIC TRANSIT TIME A.US/M : 2 SONIC TRANSIT TIME
B.K/M3 : 3 BULK DENSITY B.K/M3 : 3 BULK DENSITY
C.V/V : 4 NEUTRON POROSITY SP.V/V : 4 NEUTRON POROSITY
. : . :
.m : .m :
.v/v : .v/v :

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

@ -1,6 +1,6 @@
**file: data\more_20_warnings.las** **file: data\more_20_warnings.las**
0, line: -1, desc: STEP parameter equal 0, replace to 0.000 0, line: -1, desc: invalid STRT: 0.000 == STOP: 0.000, will be replace to actually
1, line: -1, desc: invalid STRT: 0.000 or STOP: 0.000, will be replace to actually 1, line: -1, desc: STEP parameter equal 0, replace to 0.000
2, line: 24, desc: can't convert string: '6.2.2' to number, set to NULL 2, line: 24, desc: can't convert string: '6.2.2' to number, set to NULL
3, line: 25, desc: not all column readed, set log value to NULL 3, line: 25, desc: not all column readed, set log value to NULL
4, line: 25, desc: not all column readed, set log value to NULL 4, line: 25, desc: not all column readed, set log value to NULL

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

@ -1,3 +1,6 @@
// (c) softland 2020
// softlandia@gmail.com
package glasio package glasio
import ( import (
@ -72,6 +75,7 @@ type LasWellInfo struct {
// at read file always code page converted to UTF // 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.toCodePage
//TODO add pointer to cfg //TODO add pointer to cfg
//TODO при создании объекта las есть возможность указать кодировку записи, нужна возможность указать явно кодировку чтения
type Las struct { type Las struct {
FileName string //file name from load FileName string //file name from load
File *os.File //the file from which we are reading File *os.File //the file from which we are reading
@ -96,24 +100,23 @@ type Las struct {
currentLine int //index of current line in readed file currentLine int //index of current line in readed file
maxWarningCount int //default maximum warning count maxWarningCount int //default maximum warning count
stdNull float64 //default null value stdNull float64 //default null value
//iCodepage cpd.IDCodePage //codepage input file - autodetected
} }
// GetStepFromData - return step from data section // GetStepFromData - return step from data section
// read 2 line from section ~A and determine step // read 2 line from section ~A and determine step
// close file // close file
// return o.Null if error occure // return Null if error occure
// если делать функцией, не методом, то придётся NULL передавать. а оно надо вообще // если делать функцией, не методом, то придётся NULL передавать. а оно надо вообще
func (o *Las) GetStepFromData() float64 { func (las *Las) GetStepFromData() float64 {
iFile, err := os.Open(o.FileName) iFile, err := os.Open(las.FileName)
if err != nil { if err != nil {
return o.Null return las.Null
} }
defer iFile.Close() defer iFile.Close()
_, iScanner, err := xlib.SeekFileStop(o.FileName, "~A") _, iScanner, err := xlib.SeekFileStop(las.FileName, "~A")
if (err != nil) || (iScanner == nil) { if (err != nil) || (iScanner == nil) {
return o.Null return las.Null
} }
s := "" s := ""
@ -131,7 +134,7 @@ func (o *Las) GetStepFromData() float64 {
} }
dept1, err = strconv.ParseFloat(s[:k], 64) dept1, err = strconv.ParseFloat(s[:k], 64)
if err != nil { if err != nil {
return o.Null return las.Null
} }
j++ j++
if j == 2 { if j == 2 {
@ -140,30 +143,30 @@ func (o *Las) GetStepFromData() float64 {
dept2 = dept1 dept2 = dept1
} }
//если мы попали сюда, то всё грусно, в файле после ~A не нашлось двух строчек с данными... или пустые строчки или комменты //если мы попали сюда, то всё грусно, в файле после ~A не нашлось двух строчек с данными... или пустые строчки или комменты
// TODO последняя строка "return o.Null" не обрабатывается в тесте // TODO последняя строка "return las.Null" не обрабатывается в тесте
return o.Null return las.Null
} }
func (o *Las) setStep(h float64) { func (las *Las) setStep(h float64) {
o.Step = h las.Step = h
} }
//SetNull - change parameter NULL in WELL INFO section and in all logs //SetNull - change parameter NULL in WELL INFO section and in all logs
func (o *Las) SetNull(aNull float64) error { func (las *Las) SetNull(aNull float64) error {
for _, l := range o.Logs { //loop by logs for _, l := range las.Logs { //loop by logs
for i := range l.log { //loop by dept step for i := range l.log { //loop by dept step
if l.log[i] == o.Null { if l.log[i] == las.Null {
l.log[i] = aNull l.log[i] = aNull
} }
} }
} }
o.Null = aNull las.Null = aNull
return nil return nil
} }
//logByIndex - return log from map by Index //logByIndex - return log from map by Index
func (o *Las) logByIndex(i int) (*LasCurve, error) { func (las *Las) logByIndex(i int) (*LasCurve, error) {
for _, v := range o.Logs { for _, v := range las.Logs {
if v.Index == i { if v.Index == i {
return &v, nil return &v, nil
} }
@ -205,6 +208,7 @@ func NewLas(outputCP ...cpd.IDCodePage) *Las {
return las return las
} }
/*
// NewLasPar - create new object with parameters // NewLasPar - create new object with parameters
func NewLasPar(lasInfo LasWellInfo) *Las { func NewLasPar(lasInfo LasWellInfo) *Las {
las := new(Las) las := new(Las)
@ -225,13 +229,14 @@ func NewLasPar(lasInfo LasWellInfo) *Las {
las.iDuplicate = 0 las.iDuplicate = 0
return las return las
} }
*/
//analize first char after ~ // selectSection - analize first char after ~
//~V - section vertion // ~V - section vertion
//~W - well info section // ~W - well info section
//~C - curve info section // ~C - curve info section
//~A - data section // ~A - data section
func (o *Las) selectSection(r rune) int { func (las *Las) selectSection(r rune) int {
switch r { switch r {
case 86: //V case 86: //V
return lasSecVertion //version section return lasSecVertion //version section
@ -302,56 +307,56 @@ func (hc *HeaderCheckRes) addNullWarning() {
// - double error on STEP parameter // - double error on STEP parameter
// - las file is WRAP == ON // - las file is WRAP == ON
// - Curve section not exist // - Curve section not exist
func (o *Las) checkHeader() (HeaderCheckRes, error) { func (las *Las) checkHeader() (HeaderCheckRes, error) {
res := make(HeaderCheckRes, 0) res := make(HeaderCheckRes, 0)
if o.Null == 0.0 { if las.Null == 0.0 {
res.addNullWarning() res.addNullWarning()
o.addWarning(TWarning{directOnRead, lasSecWellInfo, -1, fmt.Sprintf("NULL parameter equal 0, replace to %4.3f", o.Null)}) las.addWarning(TWarning{directOnRead, lasSecWellInfo, -1, fmt.Sprintf("NULL parameter equal 0, replace to %4.3f", las.Null)})
} }
if o.Step == 0.0 { if las.Step == 0.0 {
res.addStepWarning() res.addStepWarning()
o.addWarning(TWarning{directOnRead, lasSecWellInfo, -1, fmt.Sprintf("STEP parameter equal 0, replace to %4.3f", o.Step)}) las.addWarning(TWarning{directOnRead, lasSecWellInfo, -1, fmt.Sprintf("STEP parameter equal 0, replace to %4.3f", las.Step)})
} }
if math.Abs(o.Stop-o.Strt) < 0.1 { if math.Abs(las.Stop-las.Strt) < 0.1 {
o.addWarning(TWarning{directOnRead, lasSecWellInfo, -1, fmt.Sprintf("invalid STRT: %4.3f or STOP: %4.3f, will be replace to actually", o.Strt, o.Stop)}) las.addWarning(TWarning{directOnRead, lasSecWellInfo, -1, fmt.Sprintf("invalid STRT: %4.3f or STOP: %4.3f, will be replace to actually", las.Strt, las.Stop)})
} }
if o.IsWraped() { if las.IsWraped() {
o.addWarning(TWarning{directOnRead, lasSecData, -1, "WRAP = YES, file ignored"}) las.addWarning(TWarning{directOnRead, lasSecData, -1, "WRAP = YES, file ignored"})
return res, fmt.Errorf("Wrapped files not support") //return 0, nil return res, fmt.Errorf("Wrapped files not support") //return 0, nil
} }
if len(o.Logs) <= 0 { if len(las.Logs) <= 0 {
o.addWarning(TWarning{directOnRead, lasSecData, -1, "section ~Curve not exist, file ignored"}) las.addWarning(TWarning{directOnRead, lasSecData, -1, "section ~Curve not exist, file ignored"})
return res, fmt.Errorf("Curve section not exist") //return 0, nil return res, fmt.Errorf("Curve section not exist") //return 0, nil
} }
return res, nil return res, nil
} }
// IsWraped - return true if WRAP == YES // IsWraped - return true if WRAP == YES
func (o *Las) IsWraped() bool { func (las *Las) IsWraped() bool {
return strings.Contains(strings.ToUpper(o.Wrap), "Y") //(strings.Index(strings.ToUpper(o.Wrap), "Y") >= 0) return strings.Contains(strings.ToUpper(las.Wrap), "Y") //(strings.Index(strings.ToUpper(o.Wrap), "Y") >= 0)
} }
// SaveWarning - save to file all warning // SaveWarning - save to file all warning
func (o *Las) SaveWarning(fileName string) error { func (las *Las) SaveWarning(fileName string) error {
if o.Warnings.Count() == 0 { if las.Warnings.Count() == 0 {
return nil return nil
} }
oFile, err := os.Create(fileName) oFile, err := os.Create(fileName)
if err != nil { if err != nil {
return err return err
} }
o.SaveWarningToFile(oFile) las.SaveWarningToFile(oFile)
oFile.Close() oFile.Close()
return nil return nil
} }
// SaveWarningToWriter - store all warning to writer, return count lines writed to // SaveWarningToWriter - store all warning to writer, return count lines writed to
func (o *Las) SaveWarningToWriter(writer *bufio.Writer) int { func (las *Las) SaveWarningToWriter(writer *bufio.Writer) int {
n := o.Warnings.Count() n := las.Warnings.Count()
if n == 0 { if n == 0 {
return 0 return 0
} }
for _, w := range o.Warnings { for _, w := range las.Warnings {
writer.WriteString(w.String()) writer.WriteString(w.String())
writer.WriteString("\n") writer.WriteString("\n")
} }
@ -359,24 +364,24 @@ func (o *Las) SaveWarningToWriter(writer *bufio.Writer) int {
} }
// SaveWarningToFile - store all warning to file, file not close. return count warning writed // SaveWarningToFile - store all warning to file, file not close. return count warning writed
func (o *Las) SaveWarningToFile(oFile *os.File) int { func (las *Las) SaveWarningToFile(oFile *os.File) int {
if oFile == nil { if oFile == nil {
return 0 return 0
} }
if o.Warnings.Count() == 0 { if las.Warnings.Count() == 0 {
return 0 return 0
} }
oFile.WriteString("**file: " + o.FileName + "**\n") oFile.WriteString("**file: " + las.FileName + "**\n")
n := o.Warnings.SaveWarningToFile(oFile) n := las.Warnings.SaveWarningToFile(oFile)
oFile.WriteString("\n") oFile.WriteString("\n")
return n return n
} }
func (o *Las) addWarning(w TWarning) { func (las *Las) addWarning(w TWarning) {
if o.Warnings.Count() < o.maxWarningCount { if las.Warnings.Count() < las.maxWarningCount {
o.Warnings = append(o.Warnings, w) las.Warnings = append(las.Warnings, w)
if o.Warnings.Count() == o.maxWarningCount { if las.Warnings.Count() == las.maxWarningCount {
o.Warnings = append(o.Warnings, TWarning{0, 0, 0, "*maximum count* of warning reached, change parameter 'maxWarningCount' in 'glas.ini'"}) las.Warnings = append(las.Warnings, TWarning{0, 0, 0, "*maximum count* of warning reached, change parameter 'maxWarningCount' in 'glas.ini'"})
} }
} }
} }
@ -384,15 +389,15 @@ func (o *Las) addWarning(w TWarning) {
// GetMnemonic - return Mnemonic from dictionary by Log Name, // GetMnemonic - return Mnemonic from dictionary by Log Name,
// if Mnemonic not found return "" // if Mnemonic not found return ""
// if Dictionary is nil, then return "" // if Dictionary is nil, then return ""
func (o *Las) GetMnemonic(logName string) string { func (las *Las) GetMnemonic(logName string) string {
if (o.LogDic == nil) || (o.VocDic == nil) { if (las.LogDic == nil) || (las.VocDic == nil) {
return "" //"-" return "" //"-"
} }
_, ok := (*o.LogDic)[logName] _, ok := (*las.LogDic)[logName]
if ok { //GOOD - название каротажа равно мнемонике if ok { //GOOD - название каротажа равно мнемонике
return logName return logName
} }
v, ok := (*o.VocDic)[logName] v, ok := (*las.VocDic)[logName]
if ok { //POOR - название загружаемого каротажа найдено в словаре подстановок, мнемоника найдена if ok { //POOR - название загружаемого каротажа найдено в словаре подстановок, мнемоника найдена
return v return v
} }
@ -405,8 +410,58 @@ func (o *Las) GetMnemonic(logName string) string {
// - file cannot be decoded to UTF-8 // - file cannot be decoded to UTF-8
// - las is wrapped // - las is wrapped
// - las file not contain Curve section // - las file not contain Curve section
func (o *Las) Open(fileName string) (int, error) { func (las *Las) Open(fileName string) (int, error) {
//TODO при создании объекта las есть возможность указать кодировку записи, нужна возможность указать явно кодировку чтения var err error
las.File, err = os.Open(fileName)
if err != nil {
return 0, err
}
defer las.File.Close()
las.FileName = fileName
//create and store Reader, this reader decode to UTF-8
las.Reader, err = cpd.NewReader(las.File)
if err != nil {
return 0, err
}
las.scanner = bufio.NewScanner(las.Reader)
las.currentLine = 0
las.LoadHeader()
// проверки на фатальные ошибки
wrongChecker := NewWrongChecker()
r := wrongChecker.check(las)
if r.wrapWrong() {
las.addWarning(TWarning{directOnRead, lasSecData, -1, "WRAP = YES, file ignored"})
return 0, fmt.Errorf("Wrapped files not support")
}
if r.curvesWrong() {
las.addWarning(TWarning{directOnRead, lasSecData, -1, "section ~Curve not exist, file ignored"})
return 0, fmt.Errorf("Curve section not exist")
}
// фатальные ошибки в заголовке исключены
// делаем стандартные проверки заголовка
stdChecker := NewStdChecker()
r = stdChecker.check(las)
if r.nullWrong() {
las.addWarning(TWarning{directOnRead, lasSecWellInfo, -1, fmt.Sprintf("NULL parameter equal 0, replace to %4.3f", las.Null)})
las.SetNull(las.stdNull)
}
if r.strtStopWrong() {
las.addWarning(TWarning{directOnRead, lasSecWellInfo, -1, fmt.Sprintf("invalid STRT: %4.3f == STOP: %4.3f, will be replace to actually", las.Strt, las.Stop)})
}
if r.stepWrong() {
las.addWarning(TWarning{directOnRead, lasSecWellInfo, -1, fmt.Sprintf("STEP parameter equal 0, replace to %4.3f", las.Step)})
h := las.GetStepFromData() // return o.Null if cannot calculate step from data
if h == las.Null {
return 0, errors.New("invalid STEP parameter and invalid step in data")
}
las.setStep(h)
}
return las.ReadDataSec(fileName)
}
/*
func (o *Las) open1(fileName string) (int, error) {
var err error var err error
o.File, err = os.Open(fileName) o.File, err = os.Open(fileName)
if err != nil { if err != nil {
@ -422,12 +477,12 @@ func (o *Las) Open(fileName string) (int, error) {
o.scanner = bufio.NewScanner(o.Reader) o.scanner = bufio.NewScanner(o.Reader)
o.currentLine = 0 o.currentLine = 0
o.LoadHeader() o.LoadHeader()
// проверка корректности данных секции WELL INFO перез загрузкой данных // проверка корректности данных секции WELL INFO перез загрузкой данных
res, err := o.checkHeader() // res содержит несколько сообщений связанных с корректностью заголовка las файла res, err := o.checkHeader() // res содержит несколько сообщений связанных с корректностью заголовка las файла
if err != nil { if err != nil {
return 0, err // дальше читать файл смысла нет, или с файл переносами или нет секции Curve ... return 0, err // дальше читать файл смысла нет, или файл с переносами или нет секции Curve ...
} }
err = nil
// обрабатываем изменение параметров las файла по результатам чтения заголовка // обрабатываем изменение параметров las файла по результатам чтения заголовка
if res.needUpdateNull() { if res.needUpdateNull() {
o.SetNull(o.stdNull) o.SetNull(o.stdNull)
@ -441,6 +496,7 @@ func (o *Las) Open(fileName string) (int, error) {
} }
return o.ReadDataSec(fileName) return o.ReadDataSec(fileName)
} }
*/
/*LoadHeader - read las file and load all section before ~A /*LoadHeader - read las file and load all section before ~A
secName: 0 - empty, 1 - Version, 2 - Well info, 3 - Curve info, 4 - A data secName: 0 - empty, 1 - Version, 2 - Well info, 3 - Curve info, 4 - A data
@ -451,25 +507,25 @@ func (o *Las) Open(fileName string) (int, error) {
5. читаем одну строку (это один параметер из известной нам секции) 5. читаем одну строку (это один параметер из известной нам секции)
Пока ошибку всегда возвращает nil, причин возвращать другое значение пока нет. Пока ошибку всегда возвращает nil, причин возвращать другое значение пока нет.
*/ */
func (o *Las) LoadHeader() error { func (las *Las) LoadHeader() error {
s := "" s := ""
var err error var err error
secNum := 0 secNum := 0
for i := 0; o.scanner.Scan(); i++ { for i := 0; las.scanner.Scan(); i++ {
s = strings.TrimSpace(o.scanner.Text()) s = strings.TrimSpace(las.scanner.Text())
o.currentLine++ las.currentLine++
if isIgnoredLine(s) { if isIgnoredLine(s) {
continue continue
} }
if s[0] == '~' { //start new section if s[0] == '~' { //start new section
secNum = o.selectSection(rune(s[1])) secNum = las.selectSection(rune(s[1]))
if secNum == lasSecData { if secNum == lasSecData {
break // dAta section read after //exit from for break // dAta section read after //exit from for
} }
} else { } else {
err = o.ReadParameter(s, secNum) //if not comment, not empty and not new section => parameter, read it err = las.ReadParameter(s, secNum) //if not comment, not empty and not new section => parameter, read it
if err != nil { if err != nil {
o.addWarning(TWarning{directOnRead, secNum, -1, fmt.Sprintf("while process parameter: '%s' occure error: %v", s, err)}) las.addWarning(TWarning{directOnRead, secNum, -1, fmt.Sprintf("while process parameter: '%s' occure error: %v", s, err)})
} }
} }
} }
@ -477,53 +533,53 @@ func (o *Las) LoadHeader() error {
} }
// ReadParameter - read one parameter // ReadParameter - read one parameter
func (o *Las) ReadParameter(s string, secNum int) error { func (las *Las) ReadParameter(s string, secNum int) error {
switch secNum { switch secNum {
case lasSecVertion: case lasSecVertion:
return o.readVersionParam(s) return las.readVersionParam(s)
case lasSecWellInfo: case lasSecWellInfo:
return o.ReadWellParam(s) return las.ReadWellParam(s)
case lasSecCurInfo: case lasSecCurInfo:
return o.readCurveParam(s) return las.readCurveParam(s)
} }
return nil return nil
} }
func (o *Las) readVersionParam(s string) error { func (las *Las) readVersionParam(s string) error {
var err error var err error
p := NewLasParam(s) p := NewLasParam(s)
switch p.Name { switch p.Name {
case "VERS": case "VERS":
o.Ver, err = strconv.ParseFloat(p.Val, 64) las.Ver, err = strconv.ParseFloat(p.Val, 64)
case "WRAP": case "WRAP":
o.Wrap = p.Val las.Wrap = p.Val
} }
return err return err
} }
//ReadWellParam - read parameter from WELL section //ReadWellParam - read parameter from WELL section
func (o *Las) ReadWellParam(s string) error { func (las *Las) ReadWellParam(s string) error {
var err error var err error
p := NewLasParam(s) p := NewLasParam(s)
switch p.Name { switch p.Name {
case "STRT": case "STRT":
o.Strt, err = strconv.ParseFloat(p.Val, 64) las.Strt, err = strconv.ParseFloat(p.Val, 64)
case "STOP": case "STOP":
o.Stop, err = strconv.ParseFloat(p.Val, 64) las.Stop, err = strconv.ParseFloat(p.Val, 64)
case "STEP": case "STEP":
o.Step, err = strconv.ParseFloat(p.Val, 64) las.Step, err = strconv.ParseFloat(p.Val, 64)
case "NULL": case "NULL":
o.Null, err = strconv.ParseFloat(p.Val, 64) las.Null, err = strconv.ParseFloat(p.Val, 64)
case "WELL": case "WELL":
if o.Ver < 2.0 { if las.Ver < 2.0 {
o.Well = p.Desc las.Well = p.Desc
} else { } else {
//o.Well = p.Val //las.Well = p.Val
o.Well = wellNameFromParam(p) las.Well = wellNameFromParam(p)
} }
} }
if err != nil { if err != nil {
o.addWarning(TWarning{directOnRead, lasSecWellInfo, -1, fmt.Sprintf("detected param: %v, unit:%v, value: %v\n", p.Name, p.Unit, p.Val)}) las.addWarning(TWarning{directOnRead, lasSecWellInfo, -1, fmt.Sprintf("detected param: %v, unit:%v, value: %v\n", p.Name, p.Unit, p.Val)})
} }
return err return err
} }
@ -532,11 +588,11 @@ func (o *Las) ReadWellParam(s string) error {
//if input name unique, return input name //if input name unique, return input name
//if input name not unique, return input name + index duplicate //if input name not unique, return input name + index duplicate
//index duplicate - Las field, increase //index duplicate - Las field, increase
func (o *Las) ChangeDuplicateLogName(name string) string { func (las *Las) ChangeDuplicateLogName(name string) string {
s := "" s := ""
if _, ok := o.Logs[name]; ok { if _, ok := las.Logs[name]; ok {
o.iDuplicate++ las.iDuplicate++
s = fmt.Sprintf("%v", o.iDuplicate) s = fmt.Sprintf("%v", las.iDuplicate)
name += s name += s
} }
return name return name
@ -548,69 +604,69 @@ func (o *Las) ChangeDuplicateLogName(name string) string {
//IName - имя каротажа в исходном файле, может повторятся //IName - имя каротажа в исходном файле, может повторятся
//Name - ключ в map хранилище, повторятся не может. если в исходном есть повторение, то Name строится добавлением к IName индекса //Name - ключ в map хранилище, повторятся не может. если в исходном есть повторение, то Name строится добавлением к IName индекса
//Mnemonic - мнемоника, берётся из словаря, если в словаре не найдено, то "" //Mnemonic - мнемоника, берётся из словаря, если в словаре не найдено, то ""
func (o *Las) readCurveParam(s string) error { func (las *Las) readCurveParam(s string) error {
l := NewLasCurve(s) l := NewLasCurve(s)
l.Init(len(o.Logs), o.GetMnemonic(l.Name), o.ChangeDuplicateLogName(l.Name), o.GetExpectedPointsCount()) l.Init(len(las.Logs), las.GetMnemonic(l.Name), las.ChangeDuplicateLogName(l.Name), las.GetExpectedPointsCount())
o.Logs[l.Name] = l //добавление в хранилище кривой каротажа с колонкой глубин las.Logs[l.Name] = l //добавление в хранилище кривой каротажа с колонкой глубин
return nil return nil
} }
//GetExpectedPointsCount - оценка количества точек по параметрам STEP, STRT, STOP //GetExpectedPointsCount - оценка количества точек по параметрам STEP, STRT, STOP
func (o *Las) GetExpectedPointsCount() int { func (las *Las) GetExpectedPointsCount() int {
var m int var m int
//TODO нужно обработать все случаи //TODO нужно обработать все случаи
if o.Step == 0.0 { if las.Step == 0.0 {
return o.ePoints return las.ePoints
} }
if math.Abs(o.Stop) > math.Abs(o.Strt) { if math.Abs(las.Stop) > math.Abs(las.Strt) {
m = int((o.Stop-o.Strt)/o.Step) + 2 m = int((las.Stop-las.Strt)/las.Step) + 2
} else { } else {
m = int((o.Strt-o.Stop)/o.Step) + 2 m = int((las.Strt-las.Stop)/las.Step) + 2
} }
if m < 0 { if m < 0 {
m = -m m = -m
} }
if m == 0 { if m == 0 {
return o.ePoints return las.ePoints
} }
return m return m
} }
//expandDept - if actually data points exceeds //expandDept - if actually data points exceeds
func (o *Las) expandDept(d *LasCurve) { func (las *Las) expandDept(d *LasCurve) {
//actual number of points more then expected //actual number of points more then expected
o.addWarning(TWarning{directOnRead, lasSecData, o.currentLine, "actual number of data lines more than expected, check: STRT, STOP, STEP"}) las.addWarning(TWarning{directOnRead, lasSecData, las.currentLine, "actual number of data lines more than expected, check: STRT, STOP, STEP"})
o.addWarning(TWarning{directOnRead, lasSecData, o.currentLine, "expand number of points"}) las.addWarning(TWarning{directOnRead, lasSecData, las.currentLine, "expand number of points"})
//ожидаем удвоения данных //ожидаем удвоения данных
o.ePoints *= 2 las.ePoints *= 2
//expand first log - dept //expand first log - dept
newDept := make([]float64, o.ePoints) newDept := make([]float64, las.ePoints)
copy(newDept, d.dept) copy(newDept, d.dept)
d.dept = newDept d.dept = newDept
newLog := make([]float64, o.ePoints) newLog := make([]float64, las.ePoints)
copy(newLog, d.dept) copy(newLog, d.dept)
d.log = newLog d.log = newLog
o.Logs[d.Name] = *d las.Logs[d.Name] = *d
//loop over other logs //loop over other logs
n := len(o.Logs) n := len(las.Logs)
var l *LasCurve var l *LasCurve
for j := 1; j < n; j++ { for j := 1; j < n; j++ {
l, _ = o.logByIndex(j) l, _ = las.logByIndex(j)
newDept := make([]float64, o.ePoints) newDept := make([]float64, las.ePoints)
copy(newDept, l.dept) copy(newDept, l.dept)
l.dept = newDept l.dept = newDept
newLog := make([]float64, o.ePoints) newLog := make([]float64, las.ePoints)
copy(newLog, l.log) copy(newLog, l.log)
l.log = newLog l.log = newLog
o.Logs[l.Name] = *l las.Logs[l.Name] = *l
} }
} }
// ReadDataSec - read section of data // ReadDataSec - read section of data
func (o *Las) ReadDataSec(fileName string) (int, error) { func (las *Las) ReadDataSec(fileName string) (int, error) {
var ( var (
v float64 v float64
err error err error
@ -621,45 +677,49 @@ func (o *Las) ReadDataSec(fileName string) (int, error) {
) )
//исходя из параметров STRT, STOP и STEP определяем ожидаемое количество строк данных //исходя из параметров STRT, STOP и STEP определяем ожидаемое количество строк данных
o.ePoints = o.GetExpectedPointsCount() las.ePoints = las.GetExpectedPointsCount()
//o.currentLine++ //o.currentLine++
n := len(o.Logs) //количество каротажей, столько колонок данных ожидаем n := len(las.Logs) //количество каротажей, столько колонок данных ожидаем
d, _ = o.logByIndex(0) //dept log d, _ = las.logByIndex(0) //dept log
s := "" s := ""
for i = 0; o.scanner.Scan(); i++ { for i = 0; las.scanner.Scan(); i++ {
o.currentLine++ las.currentLine++
if i == o.ePoints { if i == las.ePoints {
o.expandDept(d) las.expandDept(d)
} }
s = strings.TrimSpace(o.scanner.Text()) s = strings.TrimSpace(las.scanner.Text())
// i счётчик не строк, а фактически считанных данных - счётчик добавлений в слайсы данных
//TODO возможно следует завести отдельный счётчик и оставить в покое счётчик цикла
if isIgnoredLine(s) { if isIgnoredLine(s) {
i-- i--
continue continue
} }
//first column is DEPT //first column is DEPT
k := strings.IndexRune(s, ' ') k := strings.IndexRune(s, ' ') //TODO вероятно получим ошибку если данные будут разделены не пробелом а табуляцией или ещё чем-то
if k < 0 { //line must have n+1 column and n separated spaces block (+1 becouse first column DEPT) if k < 0 { //line must have n+1 column and n separated spaces block (+1 becouse first column DEPT)
o.addWarning(TWarning{directOnRead, lasSecData, o.currentLine, fmt.Sprintf("line: %d is empty, ignore", o.currentLine)}) las.addWarning(TWarning{directOnRead, lasSecData, las.currentLine, fmt.Sprintf("line: %d is empty, ignore", las.currentLine)})
i-- i--
continue continue
} }
dept, err = strconv.ParseFloat(s[:k], 64) dept, err = strconv.ParseFloat(s[:k], 64)
if err != nil { if err != nil {
o.addWarning(TWarning{directOnRead, lasSecData, o.currentLine, fmt.Sprintf("first column '%s' not numeric, ignore", s[:k])}) las.addWarning(TWarning{directOnRead, lasSecData, las.currentLine, fmt.Sprintf("first column '%s' not numeric, ignore", s[:k])})
i-- i--
continue continue
} }
d.dept[i] = dept d.dept[i] = dept
// проверка шага у первых двух точек данных и сравнение с параметром step
//TODO данную проверку следует делать через Checker
if i > 1 { if i > 1 {
if math.Pow(((dept-d.dept[i-1])-o.Step), 2) > 0.1 { if math.Pow(((dept-d.dept[i-1])-las.Step), 2) > 0.1 {
o.addWarning(TWarning{directOnRead, lasSecData, o.currentLine, fmt.Sprintf("actual step %5.2f ≠ global STEP %5.2f", (dept - d.dept[i-1]), o.Step)}) las.addWarning(TWarning{directOnRead, lasSecData, las.currentLine, fmt.Sprintf("actual step %5.2f ≠ global STEP %5.2f", (dept - d.dept[i-1]), las.Step)})
} }
} }
// проверка шага между точками [i-1, i] и точками [i-2, i-1] обнаружение немонотонности колонки глубин
if i > 2 { if i > 2 {
if math.Pow(((dept-d.dept[i-1])-(d.dept[i-1]-d.dept[i-2])), 2) > 0.1 { if math.Pow(((dept-d.dept[i-1])-(d.dept[i-1]-d.dept[i-2])), 2) > 0.1 {
o.addWarning(TWarning{directOnRead, lasSecData, o.currentLine, fmt.Sprintf("step %5.2f ≠ previously step %5.2f", (dept - d.dept[i-1]), (d.dept[i-1] - d.dept[i-2]))}) las.addWarning(TWarning{directOnRead, lasSecData, las.currentLine, fmt.Sprintf("step %5.2f ≠ previously step %5.2f", (dept - d.dept[i-1]), (d.dept[i-1] - d.dept[i-2]))})
dept = d.dept[i-1] + o.Step dept = d.dept[i-1] + las.Step
} }
} }
@ -669,22 +729,22 @@ func (o *Las) ReadDataSec(fileName string) (int, error) {
iSpace := strings.IndexRune(s, ' ') iSpace := strings.IndexRune(s, ' ')
switch iSpace { switch iSpace {
case -1: //не все колонки прочитаны, а пробелов уже нет... пробуем игнорировать сроку заполняя оставшиеся каротажи NULLами case -1: //не все колонки прочитаны, а пробелов уже нет... пробуем игнорировать сроку заполняя оставшиеся каротажи NULLами
o.addWarning(TWarning{directOnRead, lasSecData, o.currentLine, "not all column readed, set log value to NULL"}) las.addWarning(TWarning{directOnRead, lasSecData, las.currentLine, "not all column readed, set log value to NULL"})
case 0: case 0:
v = o.Null v = las.Null
case 1: case 1:
v, err = strconv.ParseFloat(s[:1], 64) v, err = strconv.ParseFloat(s[:1], 64)
default: default:
v, err = strconv.ParseFloat(s[:iSpace], 64) //strconv.ParseFloat(s[:iSpace-1], 64) v, err = strconv.ParseFloat(s[:iSpace], 64) //strconv.ParseFloat(s[:iSpace-1], 64)
} }
if err != nil { if err != nil {
o.addWarning(TWarning{directOnRead, lasSecData, o.currentLine, fmt.Sprintf("can't convert string: '%s' to number, set to NULL", s[:iSpace-1])}) las.addWarning(TWarning{directOnRead, lasSecData, las.currentLine, fmt.Sprintf("can't convert string: '%s' to number, set to NULL", s[:iSpace-1])})
v = o.Null v = las.Null
} }
l, err = o.logByIndex(j) l, err = las.logByIndex(j)
if err != nil { if err != nil {
o.nPoints = i las.nPoints = i
return i, errors.New("internal ERROR, func (o *Las) readDataSec()::o.logByIndex(j) return error") return i, errors.New("internal ERROR, func (las *Las) readDataSec()::las.logByIndex(j) return error")
} }
l.dept[i] = dept l.dept[i] = dept
l.log[i] = v l.log[i] = v
@ -693,20 +753,21 @@ func (o *Las) ReadDataSec(fileName string) (int, error) {
//остаток - последняя колонка //остаток - последняя колонка
v, err = strconv.ParseFloat(s, 64) v, err = strconv.ParseFloat(s, 64)
if err != nil { if err != nil {
o.addWarning(TWarning{directOnRead, lasSecData, o.currentLine, "not all column readed, set log value to NULL"}) las.addWarning(TWarning{directOnRead, lasSecData, las.currentLine, "not all column readed, set log value to NULL"})
v = o.Null v = las.Null
} }
l, err = o.logByIndex(n - 1) l, err = las.logByIndex(n - 1)
if err != nil { if err != nil {
o.nPoints = i las.nPoints = i
return i, errors.New("internal ERROR, func (o *Las) readDataSec()::o.logByIndex(j) return error on last column") return i, errors.New("internal ERROR, func (las *Las) readDataSec()::las.logByIndex(j) return error on last column")
} }
l.dept[i] = dept l.dept[i] = dept
l.log[i] = v l.log[i] = v
} }
//i - actually readed lines and add (.) to data array //i - actually readed lines and add (.) to data array
//crop logs to actually len //crop logs to actually len
err = o.setActuallyNumberPoints(i) //TODO перенести в Open()
err = las.setActuallyNumberPoints(i)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -714,32 +775,32 @@ func (o *Las) ReadDataSec(fileName string) (int, error) {
} }
// NumPoints - return actually number of points in data // NumPoints - return actually number of points in data
func (o *Las) NumPoints() int { func (las *Las) NumPoints() int {
return o.nPoints return las.nPoints
} }
//Dept - return slice of DEPT curve (first column) //Dept - return slice of DEPT curve (first column)
func (o *Las) Dept() []float64 { func (las *Las) Dept() []float64 {
d, err := o.logByIndex(0) d, err := las.logByIndex(0)
if err != nil { if err != nil {
return nil return nil
} }
return d.dept return d.dept
} }
func (o *Las) setActuallyNumberPoints(numPoints int) error { func (las *Las) setActuallyNumberPoints(numPoints int) error {
if numPoints <= 0 { if numPoints <= 0 {
o.nPoints = 0 las.nPoints = 0
return errors.New("internal ERROR, func (o *Las) setActuallyNumberPoints(), actually number of points <= 0") return errors.New("internal ERROR, func (las *Las) setActuallyNumberPoints(), actually number of points <= 0")
} }
if numPoints > len(o.Dept()) { if numPoints > len(las.Dept()) {
o.nPoints = 0 las.nPoints = 0
return errors.New("internal ERROR, func (o *Las) setActuallyNumberPoints(), actually number of points > then exist data") return errors.New("internal ERROR, func (las *Las) setActuallyNumberPoints(), actually number of points > then exist data")
} }
for _, l := range o.Logs { for _, l := range las.Logs {
l.SetLen(numPoints) l.SetLen(numPoints)
} }
o.nPoints = numPoints las.nPoints = numPoints
return nil return nil
} }
@ -821,15 +882,15 @@ func (o *Las) SaveToFile(fileName string, useMnemonic ...bool) error {
//rewrite if file exist //rewrite if file exist
//if useMnemonic == true then on save using std mnemonic on ~Curve section //if useMnemonic == true then on save using std mnemonic on ~Curve section
//TODO las have field filename of readed las file, after save filename must update or not? warning occure on write for what file? //TODO las have field filename of readed las file, after save filename must update or not? warning occure on write for what file?
func (o *Las) Save(fileName string, useMnemonic ...bool) error { func (las *Las) Save(fileName string, useMnemonic ...bool) error {
var ( var (
err error err error
bufToSave []byte bufToSave []byte
) )
if len(useMnemonic) > 0 { if len(useMnemonic) > 0 {
bufToSave, err = o.SaveToBuf(true) bufToSave, err = las.SaveToBuf(true)
} else { } else {
bufToSave, err = o.SaveToBuf(false) bufToSave, err = las.SaveToBuf(false)
} }
if err != nil { if err != nil {
return err return err
@ -851,22 +912,22 @@ func (o *Las) Save(fileName string, useMnemonic ...bool) error {
// rewrite if file exist // rewrite if file exist
// if useMnemonic == true then on save using std mnemonic on ~Curve section // if useMnemonic == true then on save using std mnemonic on ~Curve section
// ir return err != nil then fatal error, returned slice is not full corrected // ir return err != nil then fatal error, returned slice is not full corrected
func (o *Las) SaveToBuf(useMnemonic bool) ([]byte, error) { func (las *Las) SaveToBuf(useMnemonic bool) ([]byte, error) {
n := len(o.Logs) //log count n := len(las.Logs) //log count
if n <= 0 { if n <= 0 {
return nil, errors.New("logs not exist") return nil, errors.New("logs not exist")
} }
var err error var err error
var b bytes.Buffer var b bytes.Buffer
fmt.Fprint(&b, _LasFirstLine) fmt.Fprint(&b, _LasFirstLine)
fmt.Fprintf(&b, _LasVersion, o.Ver) fmt.Fprintf(&b, _LasVersion, las.Ver)
fmt.Fprint(&b, _LasWrap) fmt.Fprint(&b, _LasWrap)
fmt.Fprint(&b, _LasWellInfoSec) fmt.Fprint(&b, _LasWellInfoSec)
fmt.Fprintf(&b, _LasStrt, o.Strt) fmt.Fprintf(&b, _LasStrt, las.Strt)
fmt.Fprintf(&b, _LasStop, o.Stop) fmt.Fprintf(&b, _LasStop, las.Stop)
fmt.Fprintf(&b, _LasStep, o.Step) fmt.Fprintf(&b, _LasStep, las.Step)
fmt.Fprintf(&b, _LasNull, o.Null) fmt.Fprintf(&b, _LasNull, las.Null)
fmt.Fprintf(&b, _LasWell, o.Well) fmt.Fprintf(&b, _LasWell, las.Well)
fmt.Fprint(&b, _LasCurvSec) fmt.Fprint(&b, _LasCurvSec)
fmt.Fprint(&b, _LasCurvDept) fmt.Fprint(&b, _LasCurvDept)
@ -874,7 +935,7 @@ func (o *Las) SaveToBuf(useMnemonic bool) ([]byte, error) {
sb.WriteString("# DEPT |") //готовим строчку с названиями каротажей глубина всегда присутствует sb.WriteString("# DEPT |") //готовим строчку с названиями каротажей глубина всегда присутствует
var l *LasCurve var l *LasCurve
for i := 1; i < n; i++ { //Пишем названия каротажей for i := 1; i < n; i++ { //Пишем названия каротажей
l, _ := o.logByIndex(i) l, _ := las.logByIndex(i)
if useMnemonic { if useMnemonic {
if len(l.Mnemonic) > 0 { if len(l.Mnemonic) > 0 {
l.Name = l.Mnemonic l.Name = l.Mnemonic
@ -888,20 +949,25 @@ func (o *Las) SaveToBuf(useMnemonic bool) ([]byte, error) {
fmt.Fprint(&b, _LasDataSec) fmt.Fprint(&b, _LasDataSec)
//write data //write data
fmt.Fprintf(&b, "%s\n", sb.String()) fmt.Fprintf(&b, "%s\n", sb.String())
dept, _ := o.logByIndex(0) dept, _ := las.logByIndex(0)
for i := 0; i < o.nPoints; i++ { //loop by dept (.) for i := 0; i < las.nPoints; i++ { //loop by dept (.)
fmt.Fprintf(&b, "%-9.3f ", dept.dept[i]) fmt.Fprintf(&b, "%-9.3f ", dept.dept[i])
for j := 1; j < n; j++ { //loop by logs for j := 1; j < n; j++ { //loop by logs
l, err = o.logByIndex(j) l, err = las.logByIndex(j)
if err != nil { if err != nil {
o.addWarning(TWarning{directOnWrite, lasSecData, i, "logByIndex() return error, log not found, panic"}) las.addWarning(TWarning{directOnWrite, lasSecData, i, "logByIndex() return error, log not found, panic"})
return nil, errors.New("logByIndex() return error, log not found, panic") return nil, errors.New("logByIndex() return error, log not found, panic")
} }
fmt.Fprintf(&b, "%-9.3f ", l.log[i]) fmt.Fprintf(&b, "%-9.3f ", l.log[i])
} }
fmt.Fprintln(&b) fmt.Fprintln(&b)
} }
r, _ := cpd.NewReaderTo(io.Reader(&b), o.oCodepage.String()) //ошибку не обрабатываем, допустимость oCodepage проверяем раньше, других причин нет r, _ := cpd.NewReaderTo(io.Reader(&b), las.oCodepage.String()) //ошибку не обрабатываем, допустимость oCodepage проверяем раньше, других причин нет
bufToSave, _ := ioutil.ReadAll(r) bufToSave, _ := ioutil.ReadAll(r)
return bufToSave, nil return bufToSave, nil
} }
// IsEmpty - test to not initialize object
func (las *Las) IsEmpty() bool {
return (las.Logs == nil)
}

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

@ -1,6 +1,192 @@
//(c) softland 2020
//softlandia@gmail.com
package glasio package glasio
// Check - import "fmt"
func Check() {
// CheckRes - результаты проверки, получааем из функции doCheck()
type CheckRes struct {
name string
section string
message string
err error
res bool
}
func (cr CheckRes) String() string {
return fmt.Sprintf("check name: %s, section: %s, desc: %s, result: %v", cr.name, cr.section, cr.message, cr.res)
}
type doCheck func(chk Check, las *Las) CheckRes
// Check - отдельная проверка, обязан реализовать функцию doCheck()
type Check struct {
name string
section string
message string
do doCheck
}
// checkResults - слайс с результатами всех проверок
type checkResults []CheckRes
func (crs checkResults) nullWrong() bool {
for _, r := range crs {
if r.name == "NullNot0" {
return true
}
}
return false
}
func (crs checkResults) stepWrong() bool {
for _, r := range crs {
if r.name == "StepNot0" {
return true
}
}
return false
}
func (crs checkResults) wrapWrong() bool {
for _, r := range crs {
if r.name == "WrapIsOn" {
return true
}
}
return false
}
func (crs checkResults) curvesWrong() bool {
for _, r := range crs {
if r.name == "CurvesNotPresent" {
return true
}
}
return false
}
func (crs checkResults) strtStopWrong() bool {
for _, r := range crs {
if r.name == "StrtStop" {
return true
}
}
return false
}
// Checker - ПРОВЕРЩИК, содержит в себе всех отдельных проверщиков,
// методом check() вызавает последовательно всех своих проверщиков,
// результаты отправляет в Logger
type Checker []Check
func (c Checker) check(las *Las) checkResults {
res := make([]CheckRes, 0)
for _, chk := range c {
r := chk.do(chk, las)
if !r.res {
res = append(res, r)
}
}
return res
}
/****************************/
// NewEmptyChecker - создание нового примитивного объекта ПРОВЕРЩИКА
// проверяет только на не пустоту объекта las
func NewEmptyChecker() Checker {
return Checker{
{chkEmptyName, chkEmptySection, "", emptyCheck},
}
}
const (
chkEmptyName = "LasNotNil"
chkEmptySection = "NoN"
)
// simpleCheck - return true if las not empty
func emptyCheck(chk Check, las *Las) CheckRes {
return CheckRes{chk.name, chk.section, chk.message, nil, !las.IsEmpty()}
}
/****************************/
// NewWrongChecker - создание нового ПРОВЕРЩИКА на ошибочность las файла.
// WRAP = ON
// section ~Curve is empty
func NewWrongChecker() Checker {
return Checker{
newWrapCheck(),
newNotPresentCurvesCheck(),
}
}
func newWrapCheck() Check {
return Check{"WrapIsOn", "~V", "WRAP = ON", wrapOn}
}
func wrapOn(chk Check, las *Las) CheckRes {
return CheckRes{chk.name, chk.section, chk.message, fmt.Errorf("Wrapped files not support"), !las.IsWraped()}
}
func newNotPresentCurvesCheck() Check {
return Check{"CurvesNotPresent", "~C", "Curve section is eptry", curvesIsEmpty}
}
func curvesIsEmpty(chk Check, las *Las) CheckRes {
return CheckRes{chk.name, chk.section, chk.message, fmt.Errorf("Curve section not exist"), len(las.Logs) > 0}
}
// NewStdChecker - создание нового стандартного ПРОВЕРЩИКА
// проверяет las
// STEP == 0
// NULL == 0
// STRT == STOP
// WELL is empty
func NewStdChecker() Checker {
return Checker{
newStepCheck(),
newNullCheck(),
newStrtStopCheck(),
newWellIsEmptyCheck(),
}
}
// Step Check
func newStepCheck() Check {
return Check{"StepNot0", "~W", "STEP == 0", stepCheck}
}
func stepCheck(chk Check, las *Las) CheckRes {
return CheckRes{chk.name, chk.section, chk.message, nil, las.Step != 0.0}
}
// Null Check
func newNullCheck() Check {
return Check{"NullNot0", "~W", "NULL == 0", nullCheck}
}
func nullCheck(chk Check, las *Las) CheckRes {
return CheckRes{chk.name, chk.section, chk.message, nil, las.Null != 0.0}
}
// STRT == STOP Check
func newStrtStopCheck() Check {
return Check{"StrtStop", "~W", "STRT == STOP", strtStopCheck}
}
func strtStopCheck(chk Check, las *Las) CheckRes {
return CheckRes{chk.name, chk.section, chk.message, nil, las.Strt != las.Stop}
}
// WELL == "" Check
func newWellIsEmptyCheck() Check {
return Check{"WellNotEmpty", "~W", "WELL == ''", wellIsEmptyCheck}
}
func wellIsEmptyCheck(chk Check, las *Las) CheckRes {
return CheckRes{chk.name, chk.section, chk.message, nil, len(las.Well) != 0}
} }

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

@ -1,37 +1,50 @@
//(c) softland 2020
//softlandia@gmail.com
package glasio package glasio
import ( import (
"fmt" "fmt"
"os" "os"
"sort" "sort"
"strings"
) )
// LasLog - store log info about the one las, fills up info from las.open() and las.check() // Logger - store log info about the one las, fills up info from las.open() and las.check()
type LasLog struct { type Logger struct {
las *Las // object from message collected las *Las // object from message collected
filename string // file to read, used for reporting // имя файла по которому формируется отчёт, используется для оформления сообщений filename string // file to read, used for reporting // имя файла по которому формируется отчёт, используется для оформления сообщений
readedNumPoints int // number points readed from file get from las.Open() readedNumPoints int // number points readed from file get from las.Open()
errorOnOpen error // status from las.Open() errorOnOpen error // status from las.Open()
msgOpen TLasWarnings // сообщения формируемые в процессе открытия las файла msgOpen TLasWarnings // сообщения формируемые в процессе открытия las файла
msgCheck tCheckMsg // информация об особых случаях, получаем из LasChecker msgCheck tCheckMsg // информация об особых проверках, получаем из LasChecker
msgCurve tCurvRprt // информация о кривых хранящихся в LAS файле, записывается в "log.info.md" msgCurve tCurvRprt // информация о кривых хранящихся в LAS файле, записывается в "log.info.md"
missMnemonic tMMnemonic // мнемоники найденные в файле и не найденные в словаре missMnemonic tMMnemonic // мнемоники найденные в файле и не найденные в словаре
} }
// NewLasLog - constructor // NewLogger - constructor
func NewLasLog(las *Las) LasLog { func NewLogger(las *Las) *Logger {
var lasLog LasLog logger := new(Logger)
lasLog.las = las logger.las = las
lasLog.filename = las.FileName logger.filename = las.FileName
lasLog.msgOpen = nil logger.msgOpen = nil
lasLog.msgCheck = make(tCheckMsg, 0, 10) logger.msgCheck = make(tCheckMsg, 0, 10)
lasLog.msgCurve = make(tCurvRprt, 0, 10) logger.msgCurve = make(tCurvRprt, 0, 10)
lasLog.missMnemonic = make(tMMnemonic) logger.missMnemonic = make(tMMnemonic)
return lasLog return logger
} }
// tCheckMsg - хранит все сообщения о специальных проверках las файла
type tCheckMsg []string type tCheckMsg []string
func (m tCheckMsg) String() string {
var sb strings.Builder
for _, msg := range m {
sb.WriteString(msg)
}
return sb.String()
}
func (m *tCheckMsg) save(f *os.File) { func (m *tCheckMsg) save(f *os.File) {
for _, msg := range *m { for _, msg := range *m {
f.WriteString(msg) f.WriteString(msg)
@ -52,9 +65,20 @@ func (m *tCheckMsg) msgFileOpenWarning(fn string, err error) string {
type tCurvRprt []string type tCurvRprt []string
func (ir *tCurvRprt) save(f *os.File, filename string) { func (cr tCurvRprt) String(filename string) string {
var sb strings.Builder
sb.WriteString(fmt.Sprintf("##logs in file: '%s'##\n", filename))
for _, s := range cr {
sb.WriteString(s)
sb.WriteString("\n")
}
sb.WriteString("\n")
return sb.String()
}
func (cr *tCurvRprt) save(f *os.File, filename string) {
fmt.Fprintf(f, "##logs in file: '%s'##\n", filename) fmt.Fprintf(f, "##logs in file: '%s'##\n", filename)
for _, s := range *ir { for _, s := range *cr {
f.WriteString(s) f.WriteString(s)
} }
f.WriteString("\n") f.WriteString("\n")
@ -62,6 +86,19 @@ func (ir *tCurvRprt) save(f *os.File, filename string) {
type tMMnemonic map[string]string type tMMnemonic map[string]string
func (mm tMMnemonic) String() string {
keys := make([]string, 0, len(mm))
for k := range mm {
keys = append(keys, k)
}
sort.Strings(keys)
var sb strings.Builder
for _, k := range keys {
sb.WriteString(mm[k] + "\n")
}
return sb.String()
}
func (mm *tMMnemonic) save(f *os.File) { func (mm *tMMnemonic) save(f *os.File) {
keys := make([]string, 0, len(*mm)) keys := make([]string, 0, len(*mm))
for k := range *mm { for k := range *mm {

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

@ -1,5 +1,5 @@
//(c) softland 2020 // (c) softland 2020
//softlandia@gmail.com // softlandia@gmail.com
package glasio package glasio
import ( import (
@ -50,7 +50,7 @@ var dSummaryCheck = []tSummaryCheck{
{fp.Join("data/missing_vers.las"), 2.0, "NO", 1670, 1660, -0.125, -999.25, "WELL", 8, 3, false}, {fp.Join("data/missing_vers.las"), 2.0, "NO", 1670, 1660, -0.125, -999.25, "WELL", 8, 3, false},
{fp.Join("data/missing_wrap.las"), 1.2, "NO", 1670, 1660, -0.125, -999.25, "ANY ET AL OIL WELL #12", 8, 3, false}, {fp.Join("data/missing_wrap.las"), 1.2, "NO", 1670, 1660, -0.125, -999.25, "ANY ET AL OIL WELL #12", 8, 3, false},
{fp.Join("data/more_20_warnings.las"), 1.2, "NO", 0.0, 0.0, 1.0, -32768.0, "6", 6, 23, true}, //in las file STEP=0.0 but this incorrect, LoadHeader replace STEP to actual from data {fp.Join("data/more_20_warnings.las"), 1.2, "NO", 0.0, 0.0, 1.0, -32768.0, "6", 6, 23, true}, //in las file STEP=0.0 but this incorrect, LoadHeader replace STEP to actual from data
{fp.Join("data/no-data-section.las"), 1.2, "NO", 0.0, 0.0, -32768, -32768.0, "6", 31, 0, true}, {fp.Join("data/no-data-section.las"), 1.2, "NO", 0.0, 0.0, 0.0, -32768.0, "6", 31, 0, true}, //in las file STEP=0.0 but this incorrect, data section contain incorrect step too, result step equal from input
{fp.Join("data/sample_bracketed_units.las"), 1.2, "NO", 1670, 1660, -0.125, -999.25, "ANY ET AL OIL WELL #12", 8, 3, true}, {fp.Join("data/sample_bracketed_units.las"), 1.2, "NO", 1670, 1660, -0.125, -999.25, "ANY ET AL OIL WELL #12", 8, 3, true},
{fp.Join("data/test-curve-sec-empty-mnemonic.las"), 1.2, "NO", 1670, 1669.75, -0.125, -999.25, "ANY ET AL OIL WELL #12", 8, 3, true}, {fp.Join("data/test-curve-sec-empty-mnemonic.las"), 1.2, "NO", 1670, 1669.75, -0.125, -999.25, "ANY ET AL OIL WELL #12", 8, 3, true},
{fp.Join("data/UWI_API_leading_zero.las"), 1.2, "NO", 1670, 1660, -0.125, -999.25, "ANY ET AL OIL WELL #12", 8, 3, true}, {fp.Join("data/UWI_API_leading_zero.las"), 1.2, "NO", 1670, 1660, -0.125, -999.25, "ANY ET AL OIL WELL #12", 8, 3, true},
@ -91,3 +91,56 @@ func TestCurveSec2(t *testing.T) {
assert.False(t, cmpLas(correct, las)) assert.False(t, cmpLas(correct, las))
assert.False(t, correct.Logs.Cmp(las.Logs)) assert.False(t, correct.Logs.Cmp(las.Logs))
} }
func TestLasCheck(t *testing.T) {
lasLog := LasCheck(fp.Join("data/test-curve-sec-empty-mnemonic+.las"))
assert.NotNil(t, lasLog)
s := lasLog.msgOpen.ToString()
assert.Empty(t, s)
s = lasLog.msgCheck.String()
assert.Empty(t, s)
s = lasLog.msgCurve.String(fp.Join("data/test-curve-sec-empty-mnemonic+.las"))
assert.Contains(t, s, "test-curve-sec-empty-mnemonic+.las'##")
// проверка на возврат 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)
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)
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)
s = lasLog.msgCurve.String(fp.Join("data/test-curve-sec-empty-mnemonic+.las"))
assert.Contains(t, s, "*input log: B internal: B mnemonic:*")
assert.Contains(t, s, "input log: SP internal: SP mnemonic: SP")
assert.Contains(t, s, "*input log: -EL-2 internal: -EL-2 mnemonic:*")
s = lasLog.missMnemonic.String()
assert.Contains(t, s, "-EL-1")
assert.NotContains(t, s, "SP")
lasLog, err = LasDeepCheck(fp.Join("data/more_20_warnings.las"), fp.Join("data/mnemonic.ini"), fp.Join("data/dic.ini"))
assert.NotNil(t, lasLog)
assert.Nil(t, err)
s = lasLog.msgOpen.ToString()
assert.Contains(t, s, "STEP parameter equal 0")
assert.Contains(t, s, "invalid STRT: 0.000 == STOP: 0.000, will be replace to actually")
s = lasLog.msgCheck.String()
assert.Empty(t, s)
s = lasLog.msgCurve.String(fp.Join("data/more_20_warnings.las"))
assert.Contains(t, s, "*input log: второй каротаж internal: второй каротаж mnemonic:*")
assert.Contains(t, s, "input log: GK internal: GK mnemonic: GR")
assert.Contains(t, s, "*input log: первый internal: первый mnemonic:*")
s = lasLog.missMnemonic.String()
assert.Contains(t, s, "NNB")
assert.Contains(t, s, "второй каротаж")
assert.NotContains(t, s, "GR")
// случай если файла нет
lasLog, err = LasDeepCheck(fp.Join("data/-test-curve-sec-empty-mnemonic+.las"), fp.Join("data/mnemonic.ini"), fp.Join("data/dic.ini"))
assert.NotNil(t, lasLog)
assert.NotNil(t, lasLog.errorOnOpen)
// случай las файл WRAP
lasLog = LasCheck(fp.Join("data/1.2/sample_wrapped.las"))
assert.Contains(t, lasLog.msgCheck.String(), "WRAP=YES")
}

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

@ -131,33 +131,6 @@ func TestLoadLasHeader(t *testing.T) {
assert.Nil(t, las) assert.Nil(t, las)
} }
/*
func TestLoadHeaderUtf(t *testing.T) {
las := NewLas()
las.iCodepage, _ = cpd.FileCodePageDetect(fp.Join("data/encodings_utf8wbom.las"))
las.LoadHeader(fp.Join("data/encodings_utf8wbom.las"))
assert.Equal(t, 1.2, las.Ver, fmt.Sprintf("<LoadHeader> file 'encodings_utf8wbom.las' readed VER: %f, expected %f", las.Ver, 1.2))
assert.Equal(t, "NO", las.Wrap, fmt.Sprintf("<LoadHeader> file 'encodings_utf8wbom.las' readed WRAP: %s, expected %s", las.Wrap, "NO"))
assert.Equal(t, 1670.0, las.Strt, fmt.Sprintf("<LoadHeader> file 'encodings_utf8wbom.las' readed STRT: %f, expected %f", las.Strt, 1670.0))
assert.Equal(t, 1660.0, las.Stop, fmt.Sprintf("<LoadHeader> file 'encodings_utf8wbom.las' readed STOP: %f, expected %f", las.Stop, 1660.0))
assert.Equal(t, -0.1250, las.Step, fmt.Sprintf("<LoadHeader> file 'encodings_utf8wbom.las' readed STEP: %f, expected %f", las.Step, -0.1250))
assert.Equal(t, -999.250, las.Null, fmt.Sprintf("<LoadHeader> file 'encodings_utf8wbom.las' readed NULL: %f, expected %f", las.Null, -999.250))
assert.Equal(t, "Скважина ºᶟᵌᴬń #12", las.Well, fmt.Sprintf("<LoadHeader> file 'encodings_utf8wbom.las' readed WELL: %s, expected %s", las.Well, "Скважина ºᶟᵌᴬń #12"))
}
func TestLoadHeaderUtf16le(t *testing.T) {
las := NewLas()
las.iCodepage, _ = cpd.FileCodePageDetect(fp.Join("data/encodings_utf16lebom.las"))
las.LoadHeader(fp.Join("data/encodings_utf16lebom.las"))
assert.Equal(t, 1.2, las.Ver, fmt.Sprintf("file 'encodings_utf16lebom.las' readed VER: %f, expected %f", las.Ver, 1.2))
assert.Equal(t, "NO", las.Wrap, fmt.Sprintf("file 'encodings_utf16lebom.las' readed WRAP: %s, expected %s", las.Wrap, "NO"))
assert.Equal(t, 1670.0, las.Strt, fmt.Sprintf("file 'encodings_utf16lebom.las' readed STRT: %f, expected %f", las.Strt, 1670.0))
assert.Equal(t, 1660.0, las.Stop, fmt.Sprintf("file 'encodings_utf16lebom.las' readed STOP: %f, expected %f", las.Stop, 1660.0))
assert.Equal(t, -0.1250, las.Step, fmt.Sprintf("file 'encodings_utf16lebom.las' readed STEP: %f, expected %f", las.Step, -0.1250))
assert.Equal(t, -999.25, las.Null, fmt.Sprintf("file 'encodings_utf16lebom.las' readed NULL: %f, expected %f", las.Null, -999.25))
assert.Equal(t, "ºᶟᵌᴬń BLOCK", las.Well, fmt.Sprintf("file 'encodings_utf16lebom.las' readed WELL: %s, expected %s", las.Well, "ºᶟᵌᴬń BLOCK"))
}*/
func TestLasSaveWarning(t *testing.T) { func TestLasSaveWarning(t *testing.T) {
las := NewLas() las := NewLas()
las.Open(fp.Join("data/more_20_warnings.las")) las.Open(fp.Join("data/more_20_warnings.las"))
@ -176,9 +149,9 @@ type tGetDataStep struct {
} }
var dGetDataStep = []tGetDataStep{ var dGetDataStep = []tGetDataStep{
{fp.Join("data/step-2-data-without-step-case1.las"), -32768.000}, {fp.Join("data/step-2-data-without-step-case1.las"), 0.0},
{fp.Join("data/step-2-data-without-step-case2.las"), -32768.000}, {fp.Join("data/step-2-data-without-step-case2.las"), 0.0},
{fp.Join("data/no-data-section.las"), -32768.000}, {fp.Join("data/no-data-section.las"), 0.0},
{fp.Join("data/step-1-normal-case.las"), 1.0}, {fp.Join("data/step-1-normal-case.las"), 1.0},
} }
@ -242,8 +215,8 @@ type tSaveLas struct {
} }
var dSaveLas = []tSaveLas{ var dSaveLas = []tSaveLas{
{fp.Join("test_files/~1251.las"), cpd.CP1251, -99.99, 0.201, 10.01, 0.01, "Примерная-101 / бис", -0.1},
// filename codepage null strt stop step well name new null // filename codepage null strt stop step well name new null
{fp.Join("test_files/~1251.las"), cpd.CP1251, -99.99, 0.201, 10.01, 0.01, "Примерная-101 / бис", -0.1},
{fp.Join("test_files/~koi8.las"), cpd.KOI8R, -99.0, 0.2, 2.0, -0.1, "Примерная-1001 /\"бис\"", -55.55}, {fp.Join("test_files/~koi8.las"), cpd.KOI8R, -99.0, 0.2, 2.0, -0.1, "Примерная-1001 /\"бис\"", -55.55},
{fp.Join("test_files/~866.las"), cpd.CP866, -909.0, 2.21, 12.1, -0.1, "Примерная-101 /\"бис\"", 5555.55}, {fp.Join("test_files/~866.las"), cpd.CP866, -909.0, 2.21, 12.1, -0.1, "Примерная-101 /\"бис\"", 5555.55},
{fp.Join("test_files/~utf-8.las"), cpd.UTF8, -999.99, 20.21, 1.0, -0.01, "Примерная-101А / бис", -999.25}, {fp.Join("test_files/~utf-8.las"), cpd.UTF8, -999.99, 20.21, 1.0, -0.01, "Примерная-101А / бис", -999.25},
@ -277,6 +250,71 @@ func TestSetNullOnEmptyLas(t *testing.T) {
assert.Equal(t, -1000.0, las.Null) assert.Equal(t, -1000.0, las.Null)
} }
func TestLasIsEmpty(t *testing.T) {
las := Las{}
assert.True(t, las.IsEmpty())
las = *NewLas()
assert.False(t, las.IsEmpty())
}
type tStdCheckLas struct {
cp cpd.IDCodePage
null float64
strt float64
stop float64
step float64
well string
testsRes [4]bool // stdCheck contain 4 test
}
var dCheckLas = []tStdCheckLas{
//codepage null strt stop step well name проверки step null strt well
{cpd.CP1251, 0.0, 0.201, 10.01, 0.01, "Примерная-101 / бис", [4]bool{true, false, true, true}},
{cpd.CP1251, -99.99, 0.201, 10.01, 0.0, "Примерная-101 / бис", [4]bool{false, true, true, true}},
{cpd.KOI8R, 0.0, 0.2, 2.0, 0.0, "Примерная-1001 /\"бис\"", [4]bool{false, false, true, true}},
{cpd.CP866, 0.0, 0.21, 0.21, 0.1, "Примерная-101 /\"бис\"", [4]bool{true, false, false, true}},
{cpd.UTF8, 0.0, 0.2, 0.2, 0.0, "", [4]bool{false, false, false, false}},
{cpd.UTF16LE, 0.0, 20.2, 1.0, -0.0, "", [4]bool{false, false, true, false}},
}
func TestLasChecker(t *testing.T) {
chkr := NewEmptyChecker()
assert.NotEqual(t, 0, len(chkr))
chkr = NewStdChecker() //стандартная проверка на step=0, null=0, strt=stop, well=""
for _, tmp := range dCheckLas {
las := makeSampleLas(tmp.cp, tmp.null, tmp.strt, tmp.stop, tmp.step, tmp.well)
assert.NotEqual(t, 0, len(chkr))
for i, chk := range chkr {
checkRes := chk.do(chk, las)
assert.Equal(t, tmp.testsRes[i], checkRes.res)
}
}
}
func TestLasChecker2(t *testing.T) {
stdChecker := NewStdChecker()
tmp := dCheckLas[0] // в данных одна ошиба, NULL=0
las := makeSampleLas(tmp.cp, tmp.null, tmp.strt, tmp.stop, tmp.step, tmp.well)
res := stdChecker.check(las)
assert.Equal(t, 1, len(res))
assert.Equal(t, res[0].name, "NullNot0")
assert.True(t, res.nullWrong())
assert.False(t, res.stepWrong())
tmp = dCheckLas[4] // все 4 ошибки
las = makeSampleLas(tmp.cp, tmp.null, tmp.strt, tmp.stop, tmp.step, tmp.well)
res = stdChecker.check(las)
assert.Equal(t, 4, len(res))
assert.Equal(t, res[0].name, "StepNot0")
assert.Equal(t, res[3].message, "WELL == ''")
assert.True(t, res.stepWrong())
las = makeSampleLas(cpd.CP866, -999.25, 0, 100, 0.2, "well") //правильные данные
res = stdChecker.check(las) //StdChecker должен вернуть пустой слайс
assert.Equal(t, 0, len(res))
}
func BenchmarkSave1(b *testing.B) { func BenchmarkSave1(b *testing.B) {
for _, tmp := range dSaveLas { for _, tmp := range dSaveLas {
las := makeSampleLas(tmp.cp, tmp.null, tmp.strt, tmp.stop, tmp.step, tmp.well) las := makeSampleLas(tmp.cp, tmp.null, tmp.strt, tmp.stop, tmp.step, tmp.well)

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

@ -5,6 +5,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"os" "os"
fp "path/filepath"
"github.com/softlandia/cpd" "github.com/softlandia/cpd"
) )
@ -82,39 +83,56 @@ func LoadLasHeader(fileName string) (*Las, error) {
return las, nil return las, nil
} }
// LasCheck - read and check las file, return object with all warnings
// считывает файл и собирает все сообщения в один объект // считывает файл и собирает все сообщения в один объект
func lasOpenCheck(filename string) LasLog { // это базовая проверка las файла, прелесть в том что здесь собираются сообщения от прочтения файла
func LasCheck(filename string) *Logger {
las := NewLas() // TODO make special constructor to initialize with global Mnemonic and Dic las := NewLas()
//las.LogDic = &Mnemonic // global var n, err := las.Open(filename)
//las.VocDic = &Dic // global var lasLog := NewLogger(las)
lasLog.readedNumPoints = n
LasLog := NewLasLog(las) lasLog.errorOnOpen = err
lasLog.msgOpen = las.Warnings
LasLog.readedNumPoints, LasLog.errorOnOpen = las.Open(filename)
LasLog.msgOpen = las.Warnings
if las.IsWraped() { if las.IsWraped() {
LasLog.msgCheck = append(LasLog.msgCheck, LasLog.msgCheck.msgFileIsWraped(filename)) lasLog.msgCheck = append(lasLog.msgCheck, lasLog.msgCheck.msgFileIsWraped(filename))
//return statLasCheck_WRAP
} }
if las.NumPoints() == 0 { if las.NumPoints() == 0 {
LasLog.msgCheck = append(LasLog.msgCheck, LasLog.msgCheck.msgFileNoData(filename)) lasLog.msgCheck = append(lasLog.msgCheck, lasLog.msgCheck.msgFileNoData(filename))
//return statLasCheck_DATA
} }
if LasLog.errorOnOpen != nil { if lasLog.errorOnOpen != nil {
LasLog.msgCheck = append(LasLog.msgCheck, LasLog.msgCheck.msgFileOpenWarning(filename, LasLog.errorOnOpen)) lasLog.msgCheck = append(lasLog.msgCheck, lasLog.msgCheck.msgFileOpenWarning(filename, lasLog.errorOnOpen))
} }
las = nil //TODO уверен это грубая ошибка, Logger хранит в себе las НАФИГА мы его тут убиваем...
return lasLog
}
// LasDeepCheck - read and check las file, curve name checked to mnemonic, return object with all warnings
// считывает файл и собирает все сообщения в один объект
func LasDeepCheck(filename, mnemonicFile, vocdicFile string) (*Logger, error) {
lasLog := LasCheck(filename)
//TODO здесь засада, LasCheck сам создаёт и читает las, более того он вообще-то его в себе хранит,
// НО в данном случае нам СТОИТ??? или НЕ СТОИТ??? об этом забывать
// мы ведь вынуждены всё равно прочитать ещё раз las файл
las := NewLas()
Mnemonic, err := LoadStdMnemonicDic(fp.Join(mnemonicFile))
if err != nil {
return nil, err
}
VocDic, err := LoadStdVocabularyDictionary(fp.Join(vocdicFile))
if err != nil {
return nil, err
}
las.LogDic = &Mnemonic
las.VocDic = &VocDic
las.Open(filename) //читаем второй раз, когда подключены словари, то чтение идёт иначе )))
for k, v := range las.Logs { for k, v := range las.Logs {
if len(v.Mnemonic) == 0 { //v.Mnemonic содержит автоопределённую стандартную мнемонику, если она пустая, значит пропущена, помечаем ** if len(v.Mnemonic) == 0 { //v.Mnemonic содержит автоопределённую стандартную мнемонику, если она пустая, значит пропущена, помечаем **
LasLog.msgCurve = append(LasLog.msgCurve, fmt.Sprintf("*input log: %s \t internal: %s \t mnemonic:%s*\n", v.IName, k, v.Mnemonic)) lasLog.msgCurve = append(lasLog.msgCurve, fmt.Sprintf("*input log: %s \t internal: %s \t mnemonic:%s*\n", v.IName, k, v.Mnemonic))
LasLog.missMnemonic[v.IName] = v.IName lasLog.missMnemonic[v.IName] = v.IName
} else { } else {
LasLog.msgCurve = append(LasLog.msgCurve, fmt.Sprintf("input log: %s \t internal: %s \t mnemonic: %s\n", v.IName, k, v.Mnemonic)) lasLog.msgCurve = append(lasLog.msgCurve, fmt.Sprintf("input log: %s \t internal: %s \t mnemonic: %s\n", v.IName, k, v.Mnemonic))
} }
} }
las = nil las = nil
return LasLog return lasLog, nil
} }

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

@ -64,7 +64,7 @@ func (o TLasWarnings) Count() int {
// ToString - make one string from all elements // ToString - make one string from all elements
// sep[0] - record separator разделитель записей // sep[0] - record separator разделитель записей
// sep[1] - field separator разделитель полей // sep[1] - field separator разделитель полей
// default separator between field ";" between record "\n" // default separator between field "," between record "\n"
// on empty container return "" // on empty container return ""
func (o *TLasWarnings) ToString(sep ...string) string { func (o *TLasWarnings) ToString(sep ...string) string {
if o.Count() == 0 { if o.Count() == 0 {

17
logger_test.go Normal file
Просмотреть файл

@ -0,0 +1,17 @@
//(c) softland 2020
//softlandia@gmail.com
package glasio
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCheckMeaasges(t *testing.T) {
chMsg := make(tCheckMsg, 2)
chMsg[0] = "message 1"
chMsg[1] = "message 2"
assert.Contains(t, chMsg.String(), "1")
assert.NotContains(t, chMsg.String(), "0")
}

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

@ -1 +1 @@
0.1.6 0.1.7