-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlas_param.go
More file actions
383 lines (345 loc) · 11.1 KB
/
las_param.go
File metadata and controls
383 lines (345 loc) · 11.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
// (c) softland 2020
// softlandia@gmail.com
// types and functions for header parameters
package glasio
import (
"fmt"
"sort"
"strconv"
"strings"
"github.com/softlandia/xlib"
)
// HeaderParam - class to store parameter from any section
// universal type for store any header parameters
// use for store parameters from sections
// ~V, ~W and other
// for curves used inherited type LasCurve
type HeaderParam struct {
Val string // parameter value
Name string // name of parameter: STOP, WELL, SP - curve name also, also matches the key used in storage
IName string
Unit string // unit of parameter
Mnemonic string
Desc string // description of parameter
lineNo int // number of line in source file
}
// HeaderSection - contain parameters of Well section
type HeaderSection struct {
name rune
params map[string]HeaderParam
parse ParseHeaderParam // function for parse one line
}
// uniqueName - return unique name
func (hs HeaderSection) uniqueName(name string) string {
if _, ok := hs.params[name]; ok {
return name + strconv.Itoa(len(hs.params))
}
return name
}
// ParseHeaderParam - function to parse one line of header
// 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
}
// defParse - parse string and create parameter of section ~V
func defParse(s string, i int) (HeaderParam, TWarning) {
p := NewHeaderParam(s, i)
return *p, TWarning{}
}
// NewOthSection - create section ~O
func NewOthSection() HeaderSection {
sec := HeaderSection{}
sec.name = 'O'
sec.params = make(map[string]HeaderParam)
sec.parse = defParse
return sec
}
// NewParSection - create section ~P
func NewParSection() HeaderSection {
sec := HeaderSection{}
sec.name = 'P'
sec.params = make(map[string]HeaderParam)
sec.parse = defParse
return sec
}
// 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
}
// curParse - parse string and create parameter of section ~C
func curParse(s string, i int) (HeaderParam, TWarning) {
p := NewCurveHeaderParam(s, i)
return *p, 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
}
// welParse12 - parse string and create parameter of section ~W
// this version for las version 1.2
func welParse12(s string, i int) (HeaderParam, TWarning) {
p := NewHeaderParam(s, i)
if p.Name == "WELL" {
p.wellName12()
}
return *p, TWarning{}
}
// welParse20 - parse string and create parameter of section ~W
// this version for las version 2.0
func welParse20(s string, i int) (HeaderParam, TWarning) {
p := NewHeaderParam(s, i)
if p.Name == "WELL" {
p.wellName20()
}
return *p, TWarning{}
}
func (p *HeaderParam) wellName12() {
p.Val, p.Desc = p.Desc, p.Val
}
func (p *HeaderParam) wellName20() {
// по умолчанию строка параметра разбирается на 4 составляющие: "имя параметра, ед измерения, значение, коментарий"
// между точкой и двоеточием ожидается единица измерения и значение параметра
// для параметра WELL пробел после точки также разбивает строку на две: ед измерения и значение
// но ТОЛЬКО для этого параметра единица измерения не существует и делать этого не следует
// таким образом собираем обратно в одно значение то, что ВОЗМОЖНО разбилось
if len(p.Unit) == 0 {
return
}
if len(p.Val) == 0 {
p.Val = p.Unit
} else {
p.Val = p.Unit + " " + p.Val
}
p.Unit = ""
}
//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", " ")
s = xlib.ReplaceAllSpace(s)
s = xlib.ReplaceSeparators(s)
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
// sample "NULL . -9999.00 : Null value"
// f[0] - name
// f[1] - unit
// f[2] - value
// f[3] - description
func ParseParamStr(s string) (f [4]string) {
f[0] = ""
f[1] = ""
f[2] = ""
f[3] = ""
s = PrepareParamStr(s)
iComma := strings.LastIndex(s, ":") //comment parse first, cut string after
commentFlag := (iComma >= 0)
if commentFlag {
f[3] = s[iComma+1:]
s = strings.TrimSpace(s[:iComma])
}
var iDot int
f[0], iDot = xlib.StrCopyStop(s, ' ', '.', ':')
f[0] = strings.TrimSpace(f[0])
if iDot >= len(s) {
return
}
s = strings.TrimSpace(s[iDot+1:])
f[1], iDot = xlib.StrCopyStop(s, ' ', ':')
f[1] = strings.TrimSpace(f[1])
if iDot >= len(s) {
return
}
s = strings.TrimSpace(s[iDot+1:])
f[2], _ = xlib.StrCopyStop(s, ':')
f[2] = strings.TrimSpace(f[2])
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
// " пс повт . мВ : 7 кр сам"
// ^^^^^^^ ^^ ^^^^^^^^
// name unit description
// f[2] - description
// f[1] - unit
// f[0] - name
func ParseCurveStr(s string) (f [3]string) {
f[0] = ""
f[1] = ""
f[2] = ""
s = PrepareParamStr(s)
iComma := strings.LastIndex(s, ":") //comment parse first, cut string after
commentFlag := (iComma >= 0)
if commentFlag {
f[2] = s[iComma+1:]
s = strings.TrimSpace(s[:iComma])
}
//if comma not found, string not change
//now s contains only name and unit
iDot := strings.Index(s, ".")
if iDot < 0 { //if dot not found, all string is Curve name
f[0] = strings.TrimSpace(s)
return
}
f[0] = strings.TrimSpace(s[:iDot])
if len(f[0]) == 0 {
f[0] = defCurveName // case empty curve name
}
f[1] = strings.TrimSpace(s[iDot+1:])
return
}
//LasCurve - class to store one log in Las
type LasCurve struct {
HeaderParam
Index int
D []float64
V []float64
}
// NewLasCurve - create new object LasCurve
// s - string from las header
// las - pointer to container
func NewLasCurve(s string, las *Las) LasCurve {
lc := LasCurve{}
curveFields := ParseCurveStr(s)
lc.IName = curveFields[0]
lc.Name = las.Logs.UniqueName(lc.IName)
lc.Unit = curveFields[1]
lc.Desc = curveFields[2]
lc.Index = len(las.Logs) // index of new curve == number of curves already in container
lc.Mnemonic = las.GetMnemonic(lc.IName) // мнемонику определяем по входному имени кривой
// вместимость слайсов для хранения данных равна количеству строк в исходном файле
lc.D = make([]float64, 0, las.NumPoints())
lc.V = make([]float64, 0, las.NumPoints())
return lc
}
// String - return LasCurve as string
func (o LasCurve) String() string {
return fmt.Sprintf("[\n{\n\"IName\": \"%s\",\n\"Name\": \"%s\",\n\"Mnemonic\": \"%s\",\n\"Unit\": \"%s\",\"Val\": \"%s\",\n\"Desc\": \"%s\"\n}\n]", o.IName, o.Name, o.Mnemonic, o.Unit, o.Val, o.Desc)
}
// Cmp - compare current curve with another
// не сравниваются хранящиеся числовые данные (сам каротаж), только описание кривой, также не сравнивается индекс
// for deep comparison with all data points stored in the container use DeepCmp
func (o *LasCurve) Cmp(curve LasCurve) (res bool) {
res = (o.HeaderParam == curve.HeaderParam)
return
}
//SetLen - crop logs to actually len
//new len must be > 0 and < exist length
func (o *LasCurve) SetLen(n int) {
if (n <= 0) || n >= len(o.D) {
return
}
t := make([]float64, n)
copy(t, o.D)
o.D = t
t = make([]float64, n)
copy(t, o.V)
o.V = t
}
// LasCurves - container to store all curves of las file
// .Cmp(curves *LasCurves) bool - compare two curves containers
type LasCurves []LasCurve
// Captions - return string represents all curve names with separators for las file
// use as comment string after section ~A
func (curves LasCurves) Captions() string {
var sb strings.Builder
sb.WriteString("# ") //готовим строчку с названиями каротажей глубина всегда присутствует
for _, curve := range curves { //Пишем названия каротажей
fmt.Fprintf(&sb, " %-8s|", curve.Name) //Собираем строчку с названиями каротажей
}
return sb.String()
}
// IsPresent - return true if curveName is already present in container
func (curves LasCurves) IsPresent(curveName string) bool {
for _, cn := range curves {
if cn.Name == curveName {
return true
}
}
return false
}
// UniqueName - make new unique name of curve if it duplicated
func (curves LasCurves) UniqueName(curveName string) string {
if curves.IsPresent(curveName) {
return curveName + strconv.Itoa(len(curves))
}
return curveName
}
// Cmp - compare current curves container with another
// сравниваются:
// количество кривых в контейнере
// два хеша от строк с именами всех кривых
func (curves LasCurves) Cmp(otheCurves LasCurves) (res bool) {
res = (len(curves) == len(otheCurves))
if res {
curvesName := make([]string, 0, len(curves))
for _, k := range curves {
curvesName = append(curvesName, k.Name)
}
sort.Strings(curvesName)
var sb strings.Builder
for _, k := range curvesName {
sb.WriteString(k)
}
h1 := xlib.StrHash(sb.String())
curvesName = curvesName[:0]
for _, k := range otheCurves {
curvesName = append(curvesName, k.Name)
}
sort.Strings(curvesName)
sb.Reset()
for _, k := range curvesName {
sb.WriteString(k)
}
h2 := xlib.StrHash(sb.String())
res = (h1 == h2)
}
return res
}