las2witsml 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|