las2witsml 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README +7 -3
- data/bin/las2witsml +9 -4
- data/lib/las2witsml.rb +3 -0
- data/lib/las_file.rb +18 -1
- data/lib/witsml_file.rb +74 -43
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 14c9e773b85635719360a9154e63d2d9aacd7422
|
4
|
+
data.tar.gz: 4bb54334c6d22e09314bb79fd5943337c7229cc7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 57254ea3787533afd554409b84af521649f466d37e0aa88b45595e582e2878821f9e2f5cd321592438ad8d88c14612f58f331fa6933a4a2ce120c13814f2e4cb
|
7
|
+
data.tar.gz: 4711d47f0e9657677421a4c00815bc7819eead4aefbfbcfe83ba6656280121fb56de13aea36fb15152a2bbb7e3093e34c3b15a28830b04de08b91d94048cc0e8
|
data/README
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
-
las2witsml -- Convert Log ASCII
|
1
|
+
las2witsml -- Convert Log ASCII Standard (LAS) files to WITSML <log> objects.
|
2
2
|
|
3
3
|
Use this script to convert LAS files to WITSML logs. The script attempts to be forgiving
|
4
4
|
of some commonly encountered variations. It can process most LAS v2 and v3 files.
|
5
5
|
|
6
|
-
Usage: las2witsml [-n name] [-u uid] [-b uid] [-l uid] [-x version] [-h] [-v] lasfile
|
6
|
+
Usage: las2witsml [-n name] [-u uid] [-b uid] [-l uid] [-x version] [-m uomfile] [-h] [-v] lasfile
|
7
7
|
-n, --namelog name Name to give the WITSML log; default 'Untitled'
|
8
8
|
-u, --uidwell uid WITSML uid of the containing well
|
9
9
|
-b, --uidwellbore uid WITSML uid of the containing wellbore
|
10
10
|
-l, --uidlog uid WITSML uid to assign the log
|
11
11
|
-x, --version version WITSML version to emit, either 1.3.1 or 1.4.1; default 1.4.1
|
12
|
+
-m, --uomfile path Path to a units of measure JSON file, mapping foreign
|
13
|
+
to WITSML units of measure e.g. https://github.com/wellstorm/las2witsml/blob/master/lib/uom.json
|
12
14
|
-v, --verbose Emit diagnostic output on stderr
|
13
15
|
-h, --help Show this message
|
14
16
|
|
@@ -22,4 +24,6 @@ History:
|
|
22
24
|
|
23
25
|
12 Jun 2012 -- gemified existing code and initial commit. (0.1.1)
|
24
26
|
14 Jun 2012 -- proper return values to shell: 0 success, 1 failure. (0.1.2)
|
25
|
-
|
27
|
+
30 Sep 2013 -- extended list of units of measure; throw exception if unrecognized uom. (0.1.3)
|
28
|
+
1 Oct 2013 -- support for external uom file (0.1.4)
|
29
|
+
4 Oct 2013 -- report all the uom conversion errors if there are any. (0.1.5)
|
data/bin/las2witsml
CHANGED
@@ -65,7 +65,7 @@ if ( !options[:url] )
|
|
65
65
|
#exit 1
|
66
66
|
end
|
67
67
|
|
68
|
-
|
68
|
+
succeed = false
|
69
69
|
ARGV.each do|a|
|
70
70
|
l2w = Las2Witsml.new
|
71
71
|
infile = File.new a, 'r'
|
@@ -79,12 +79,17 @@ ARGV.each do|a|
|
|
79
79
|
end
|
80
80
|
begin
|
81
81
|
succeed = l2w.run infile, outfile, options[:uw] || "", options[:uwb] || "", options[:ul] || "", options[:name] || 'Untitled', version, options[:v] != false, options[:uom_file]
|
82
|
-
succeed ? 0 : 1
|
83
82
|
rescue => e
|
84
|
-
$stderr.puts e
|
85
|
-
1
|
83
|
+
$stderr.puts e
|
84
|
+
exit 1
|
86
85
|
end
|
87
86
|
end
|
88
87
|
|
88
|
+
if succeed
|
89
|
+
exit 0
|
90
|
+
else
|
91
|
+
exit 1
|
92
|
+
end
|
93
|
+
|
89
94
|
|
90
95
|
|
data/lib/las2witsml.rb
CHANGED
data/lib/las_file.rb
CHANGED
@@ -16,13 +16,30 @@ class LasFile
|
|
16
16
|
:start_measured_depth_index, :stop_measured_depth_index,
|
17
17
|
:start_date_time_index, :stop_date_time_index,
|
18
18
|
:null_value, :service_company, :curve_values,
|
19
|
-
:elevation_kelly_bushing, :log_measured_from, :permanent_datum, :above_permanent_datum
|
19
|
+
:elevation_kelly_bushing, :log_measured_from, :permanent_datum, :above_permanent_datum,
|
20
|
+
:elevation_permanent_datum
|
20
21
|
|
21
22
|
def initialize(io)
|
22
23
|
@log_curve_infos = []
|
23
24
|
@curve_values = []
|
24
25
|
@in = io
|
25
26
|
@next_line=nil
|
27
|
+
|
28
|
+
@measured_depth_unit =nil
|
29
|
+
@start_measured_depth_index=nil
|
30
|
+
@stop_measured_depth_index=nil
|
31
|
+
@start_date_time_index=nil
|
32
|
+
@stop_date_time_index=nil
|
33
|
+
@null_value=nil
|
34
|
+
@service_company=nil
|
35
|
+
@curve_values=nil
|
36
|
+
@elevation_kelly_bushing=nil
|
37
|
+
@log_measured_from=nil
|
38
|
+
@permanent_datum=nil
|
39
|
+
@above_permanent_datum=nil
|
40
|
+
@elevation_permanent_datum = nil
|
41
|
+
|
42
|
+
|
26
43
|
end
|
27
44
|
|
28
45
|
def process verbose=false
|
data/lib/witsml_file.rb
CHANGED
@@ -6,7 +6,15 @@ require 'uom'
|
|
6
6
|
class WitsmlFile
|
7
7
|
class UnrecognizedUnitException < Exception
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
|
+
class ConversionError < Exception
|
11
|
+
attr_accessor :bad_units
|
12
|
+
def initialize bad_units
|
13
|
+
super "Units conversion problems: #{bad_units}"
|
14
|
+
@bad_units = bad_units
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
10
18
|
def initialize(out, witsml_version = 1410, uom_file = nil)
|
11
19
|
@indent = 0
|
12
20
|
@out = out
|
@@ -51,7 +59,7 @@ class WitsmlFile
|
|
51
59
|
get_index = lambda do |values|
|
52
60
|
date = values[date_index]
|
53
61
|
#$stderr.puts "date #{date} fmt = #{date_fmt}"
|
54
|
-
|
62
|
+
|
55
63
|
if date_fmt == '1' then
|
56
64
|
#$stderr.puts "date = #{date}"
|
57
65
|
offset = las_file.start_date_time_index
|
@@ -74,15 +82,19 @@ class WitsmlFile
|
|
74
82
|
end
|
75
83
|
[new_lcis, index_lci, is_index_index, get_index]
|
76
84
|
end
|
77
|
-
|
78
|
-
|
85
|
+
|
86
|
+
|
79
87
|
def not_empty s
|
80
88
|
s && s.length > 0
|
81
89
|
end
|
82
90
|
|
91
|
+
# Populate the WITSML log from a LAS file.
|
92
|
+
# Return nil on success.
|
93
|
+
# Raise a ConversionError exception containing a problem description on failure.
|
94
|
+
|
83
95
|
def from_las_file(las_file, uid_well='$UIDWELL', uid_wellbore='$UIDWELLBORE', uid='$UID', name='$NAME', verbose=false)
|
84
96
|
new_lcis, _, is_index_index, get_index = digest_las(las_file) #unused index_lci
|
85
|
-
|
97
|
+
|
86
98
|
if @witsml_version >= 1410
|
87
99
|
ns = 'http://www.witsml.org/schemas/1series'
|
88
100
|
vers = '1.4.1.0'
|
@@ -91,6 +103,9 @@ class WitsmlFile
|
|
91
103
|
vers = '1.3.1.1'
|
92
104
|
end
|
93
105
|
|
106
|
+
# Accumulate bad unit references in an array
|
107
|
+
bad_units = []
|
108
|
+
|
94
109
|
index_curve = new_lcis[0].mnemonic # assume first column is index
|
95
110
|
add_element('logs',{'xmlns'=>ns, 'version'=>vers}) do
|
96
111
|
add_element('log', {'uidWell' => uid_well, 'uidWellbore'=>uid_wellbore, 'uid' => uid}) do
|
@@ -101,16 +116,20 @@ class WitsmlFile
|
|
101
116
|
add_text_element 'serviceCompany', las_file.service_company if not_empty(las_file.service_company)
|
102
117
|
add_text_element 'description', 'Created by Wellstorm LAS Import'
|
103
118
|
|
104
|
-
|
105
|
-
|
119
|
+
begin
|
120
|
+
measured_depth_unit = normalize_unit(las_file.measured_depth_unit);
|
121
|
+
rescue UnrecognizedUnitException => e
|
122
|
+
# record the error, set a default value for unit, and continue
|
123
|
+
bad_units.push( {:name => 'measured depth', :unit => e.message})
|
124
|
+
measured_depth_unit = 'unitless'
|
125
|
+
end
|
126
|
+
|
106
127
|
if measured_depth_unit then
|
107
128
|
add_text_element 'indexType', 'measured depth'
|
108
129
|
add_text_element 'startIndex', las_file.start_measured_depth_index, {'uom' => measured_depth_unit} if las_file.start_measured_depth_index
|
109
130
|
add_text_element 'endIndex', las_file.stop_measured_depth_index, {'uom' => measured_depth_unit} if las_file.stop_measured_depth_index
|
110
131
|
else
|
111
132
|
add_text_element 'indexType', 'date time'
|
112
|
-
|
113
|
-
|
114
133
|
#puts ("start index in LAS is #{las_file.start_date_time_index}")
|
115
134
|
|
116
135
|
add_text_element 'startDateTimeIndex', las_file.start_date_time_index.iso8601 if las_file.start_date_time_index
|
@@ -118,14 +137,14 @@ class WitsmlFile
|
|
118
137
|
end
|
119
138
|
#add_text_element 'direction'
|
120
139
|
|
121
|
-
if @witsml_version >= 1410
|
140
|
+
if @witsml_version >= 1410 then
|
122
141
|
add_text_element 'indexCurve', index_curve
|
123
142
|
else
|
124
143
|
add_text_element 'indexCurve', index_curve, {'columnIndex'=>1}
|
125
144
|
end
|
126
145
|
add_text_element 'nullValue', las_file.null_value
|
127
146
|
|
128
|
-
|
147
|
+
|
129
148
|
begin
|
130
149
|
# use this new array of curve values we build
|
131
150
|
tempfile = Tempfile.new 'las2witsml'
|
@@ -140,53 +159,65 @@ class WitsmlFile
|
|
140
159
|
tempfile << idx
|
141
160
|
#$stderr.puts "idx #{idx}"
|
142
161
|
values.each_with_index do |v, i|
|
143
|
-
|
162
|
+
|
144
163
|
start[i] = idx if start[i].nil? and v != las_file.null_value
|
145
164
|
stop[i] = idx if v != las_file.null_value
|
146
165
|
tempfile << ",#{v}" if !is_index_index.call(i)
|
147
166
|
|
148
|
-
|
167
|
+
# $stderr.puts "put #{v} on tempfile"
|
149
168
|
end
|
150
169
|
tempfile << $/
|
151
170
|
nil
|
152
171
|
end
|
153
172
|
$stderr.puts "done adding lines to tempfile" if verbose
|
154
|
-
|
173
|
+
|
155
174
|
tempfile.rewind
|
156
175
|
|
157
176
|
$stderr.puts "rewound #{tempfile}" if verbose
|
158
|
-
|
177
|
+
|
159
178
|
# Now we can build the lcis, surveying each curve for its min/max indexes
|
160
179
|
new_lcis.each_with_index do |lci, index|
|
161
|
-
|
180
|
+
begin
|
181
|
+
add_log_curve_info lci, (index + 1), start[index+1], stop[index+1], measured_depth_unit
|
182
|
+
rescue UnrecognizedUnitException => e
|
183
|
+
bad_units.push( {:name => lci.mnemonic, :unit => e.message})
|
184
|
+
end
|
162
185
|
end
|
163
186
|
|
164
187
|
$stderr.puts "added #{new_lcis.length} LCIs" if verbose
|
165
|
-
|
188
|
+
|
166
189
|
|
167
190
|
# Now add the curve data
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
191
|
+
if bad_units.length == 0 then
|
192
|
+
add_element 'logData' do
|
193
|
+
if @witsml_version >= 1410
|
194
|
+
add_text_element 'mnemonicList', new_lcis.map{|lci| lci.mnemonic}.join(',')
|
195
|
+
add_text_element 'unitList', new_lcis.map{|lci| lci.unit}.join(',')
|
196
|
+
end
|
173
197
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
198
|
+
n = 0
|
199
|
+
tempfile.each_line do |values|
|
200
|
+
add_text_element 'data', values
|
201
|
+
n = n + 1
|
202
|
+
$stderr.puts "converted #{n} lines to WITSML" if (verbose && n % 1000 == 0 )
|
203
|
+
end
|
204
|
+
$stderr.puts "converted a total of #{n} lines to WITSML" if verbose
|
179
205
|
end
|
180
|
-
$stderr.puts "converted a total of #{n} lines to WITSML" if verbose
|
181
206
|
end
|
182
|
-
|
207
|
+
ensure
|
183
208
|
tempfile.close true
|
184
209
|
end
|
185
|
-
|
186
210
|
end
|
187
211
|
end
|
212
|
+
#return nil if all succeeded, or a problem hash if not
|
213
|
+
if bad_units.length == 0
|
214
|
+
return nil
|
215
|
+
else
|
216
|
+
e = ConversionError.new bad_units
|
217
|
+
raise e
|
218
|
+
end
|
188
219
|
end
|
189
|
-
|
220
|
+
|
190
221
|
private
|
191
222
|
def add_element name, attrs = {}, one_liner = false
|
192
223
|
@indent.times {@out.write " "}
|
@@ -244,7 +275,7 @@ class WitsmlFile
|
|
244
275
|
|
245
276
|
|
246
277
|
def make_time_indexes(lcis)
|
247
|
-
|
278
|
+
|
248
279
|
# Typically we see DATE and TIME
|
249
280
|
# We can also see only TIME in which case we expect long integer seconds since 1970
|
250
281
|
# (There's no spec that says that; but this data comes from SLB's IDEAL which uses Unix epoch)
|
@@ -256,7 +287,7 @@ class WitsmlFile
|
|
256
287
|
|
257
288
|
$stderr.puts("date_index #{date_index}, time_index #{time_index}")
|
258
289
|
|
259
|
-
|
290
|
+
|
260
291
|
if !time_index then
|
261
292
|
#assume time will be in the next column
|
262
293
|
time_index = (date_index + 1) if date_index
|
@@ -277,7 +308,7 @@ class WitsmlFile
|
|
277
308
|
raise "No TIME or DATE" if (!time_index && !date_index)
|
278
309
|
|
279
310
|
[date_index, time_index, date_fmt]
|
280
|
-
|
311
|
+
|
281
312
|
end
|
282
313
|
|
283
314
|
def normalize_unit(las_unit)
|
@@ -287,15 +318,15 @@ class WitsmlFile
|
|
287
318
|
|
288
319
|
return las_unit if !las_unit
|
289
320
|
|
290
|
-
# just a few random ones from CWLS web site:
|
291
|
-
# RHOB .K/M3 45 350 02 00 : 2 BULK DENSITY
|
292
|
-
#NPHI .VOL/VO 42 890 00 00 : 3 NEUTRON POROSITY - SANDSTONE
|
293
|
-
#MSFL .OHMM 20 270 01 00 : 4 Rxo RESISTIVITY
|
294
|
-
# SP .MV 07 010 01 00 : 8 SPONTANEOUS POTENTIAL
|
295
|
-
#GR .GAPI 45 310 01 00 : 9 GAMMA RAY
|
296
|
-
#CALI .MM 45 280 01 00 : 10 CALIPER
|
297
|
-
#DRHO .K/M3 45 356 01 00 : 11 DENSITY CORRECTION
|
298
|
-
|
321
|
+
# just a few random ones from CWLS web site:
|
322
|
+
# RHOB .K/M3 45 350 02 00 : 2 BULK DENSITY
|
323
|
+
#NPHI .VOL/VO 42 890 00 00 : 3 NEUTRON POROSITY - SANDSTONE
|
324
|
+
#MSFL .OHMM 20 270 01 00 : 4 Rxo RESISTIVITY
|
325
|
+
# SP .MV 07 010 01 00 : 8 SPONTANEOUS POTENTIAL
|
326
|
+
#GR .GAPI 45 310 01 00 : 9 GAMMA RAY
|
327
|
+
#CALI .MM 45 280 01 00 : 10 CALIPER
|
328
|
+
#DRHO .K/M3 45 356 01 00 : 11 DENSITY CORRECTION
|
329
|
+
|
299
330
|
retval = @uom.translate las_unit
|
300
331
|
if !retval
|
301
332
|
raise UnrecognizedUnitException, las_unit
|