Class: WitsmlFile

Inherits:
Object
  • Object
show all
Defined in:
lib/witsml_file.rb

Defined Under Namespace

Classes: ConversionError, UnrecognizedUnitException

Instance Method Summary collapse

Constructor Details

#initialize(out, witsml_version = 1410, uom_file = nil) ⇒ WitsmlFile

Returns a new instance of WitsmlFile.



18
19
20
21
22
23
# File 'lib/witsml_file.rb', line 18

def initialize(out, witsml_version = 1410, uom_file = nil)
  @indent = 0
  @out = out
  @witsml_version = witsml_version
  @uom = Uom.new uom_file
end

Instance Method Details

#digest_las(las_file) ⇒ Object



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
# File 'lib/witsml_file.rb', line 25

def digest_las(las_file)
  #pre chew the las

  #merge date and time
  lcis = las_file.log_curve_infos
  
  #Set these variables, which depend on whether we have a time or a depth log:
  # new_lcis : possibly modified (to merge date+time) list of logCurveInfos
  # index_lci: the LCI of the index curve
  # is_index_index: proc to test the given integer to see whether it is one of the possibly one or two index curve indexes
  # get_index: proc to extract the index from an array of values
  
  if las_file.measured_depth_unit then
    # it's a depth log
    # use the unaltered array of lcis
    new_lcis = lcis
    index_lci = lcis[0]
    
    is_index_index = lambda {|i| (i == 0) }
    get_index = lambda { |values| values[0] }
    
  else
    
    #it's a time log
    date_index, time_index, date_fmt = make_time_indexes(lcis)
    
    # make the new lci for the merged index. Name it 'DATETIME'
    index_lci =  LogCurveInfo.new('DATETIME')
    
    rest_lcis = lcis.reject {|lci| ['time', 'date'].member?(lci.mnemonic.downcase)}    
    
    # use this new array of lcis now
    new_lcis = [index_lci] + rest_lcis
    is_index_index = lambda {|i| (i == time_index || i == date_index) }
    get_index = lambda do |values|
      date = values[date_index]
      #$stderr.puts "date #{date} fmt = #{date_fmt}"
      
      if date_fmt == '1' then
        #$stderr.puts "date = #{date}"
        offset = las_file.start_date_time_index
        dtf = date.to_f
        if (dtf < 86400000 && offset) then
          dt = Time.at(date.to_f + offset.to_f).iso8601
        else
          dt = Time.at(date.to_f).iso8601
        end
      else
        #if we have "mmddyy", munge it so the parser works
        date = date.sub(/(\d\d)(\d\d)(\d\d)/, '\2/\3/\1') if date_fmt == 'yymmdd'
        time = values[time_index]
        # Pason does not put colons between time components; SLB does:
        time = time.sub(/(\d\d)(\d\d)(\d\d)/, '\1:\2:\3') if /\d\d\d\d\d\d/=~ time
        dt = Time.parse(time + ' ' + date).iso8601
      end
      dt
    end        
  end
  [new_lcis, index_lci, is_index_index, get_index]
end

#from_las_file(las_file, uid_well = '$UIDWELL', uid_wellbore = '$UIDWELLBORE', uid = '$UID', name = '$NAME', verbose = false) ⇒ Object

Populate the WITSML log from a LAS file. Return nil on success. Raise a ConversionError exception containing a problem description on failure.



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
# File 'lib/witsml_file.rb', line 95

def from_las_file(las_file, uid_well='$UIDWELL', uid_wellbore='$UIDWELLBORE', uid='$UID', name='$NAME', verbose=false)
  new_lcis, _, is_index_index, get_index = digest_las(las_file)  #unused index_lci
  
  if @witsml_version >= 1410
    ns = 'http://www.witsml.org/schemas/1series'
    vers = '1.4.1.0'
  else
    ns = 'http://www.witsml.org/schemas/131'
    vers = '1.3.1.1'
  end
  
  # Accumulate bad unit references in an array
  bad_units = []

  index_curve = new_lcis[0].mnemonic  # assume first column is index
  add_element('logs',{'xmlns'=>ns, 'version'=>vers}) do
    add_element('log', {'uidWell' => uid_well, 'uidWellbore'=>uid_wellbore, 'uid' => uid}) do
      add_text_element  'nameWell', name
      add_text_element  'nameWellbore', name
      add_text_element  'name', name
      #add_text_element  'dataRowCount', las_file.curve_values.length
      add_text_element  'serviceCompany', las_file.service_company if not_empty(las_file.service_company)
      add_text_element  'description', 'Created by Wellstorm LAS Import'

      begin
        measured_depth_unit = normalize_unit(las_file.measured_depth_unit);
      rescue UnrecognizedUnitException => e
        # record the error, set a default value for unit, and continue
        bad_units.push( {:name => 'measured depth', :unit => e.message})
        measured_depth_unit = 'unitless'
      end

      if measured_depth_unit then
        add_text_element  'indexType', 'measured depth'
        add_text_element  'startIndex', las_file.start_measured_depth_index, {'uom' => measured_depth_unit} if las_file.start_measured_depth_index
        add_text_element  'endIndex', las_file.stop_measured_depth_index, {'uom' => measured_depth_unit} if las_file.stop_measured_depth_index        
      else
        add_text_element  'indexType', 'date time'
        #puts ("start index in LAS is #{las_file.start_date_time_index}")

        add_text_element  'startDateTimeIndex', las_file.start_date_time_index.iso8601 if las_file.start_date_time_index
        add_text_element  'endDateTimeIndex', las_file.stop_date_time_index.iso8601 if las_file.stop_date_time_index
      end 
      #add_text_element  'direction' 
      
      if @witsml_version >= 1410 then
        add_text_element  'indexCurve', index_curve
      else
        add_text_element  'indexCurve', index_curve, {'columnIndex'=>1}
      end
      add_text_element  'nullValue', las_file.null_value

      
      begin
        # use this new array of curve values we build
        tempfile = Tempfile.new 'las2witsml'

        #keep track of start/stop for each channel
        start = []
        stop = []

        las_file.each_data_line(verbose) do |values|
          #$stderr.puts values
          idx = get_index.call(values)
          tempfile << idx
          #$stderr.puts "idx #{idx}"
          values.each_with_index do |v, i|

            start[i] = idx if start[i].nil? and v != las_file.null_value
            stop[i] = idx if v != las_file.null_value
            tempfile << ",#{v}" if  !is_index_index.call(i) 

            # $stderr.puts "put #{v} on tempfile"
          end
          tempfile << $/
          nil
        end
        $stderr.puts "done adding lines to tempfile" if verbose   
        
        tempfile.rewind 

        $stderr.puts "rewound #{tempfile}" if verbose
        
        # Now we can build the lcis, surveying each curve for its min/max indexes
        new_lcis.each_with_index do |lci, index|
          begin
            add_log_curve_info lci, (index + 1), start[index+1],  stop[index+1], measured_depth_unit
          rescue UnrecognizedUnitException => e
            bad_units.push( {:name => lci.mnemonic, :unit => e.message})          
          end
        end

        $stderr.puts "added #{new_lcis.length} LCIs" if verbose   
        
        
        # Now add the curve data
        if bad_units.length == 0 then 
          add_element 'logData' do
            if @witsml_version >= 1410
              add_text_element 'mnemonicList', new_lcis.map{|lci| lci.mnemonic}.join(',')
              add_text_element 'unitList', new_lcis.map{|lci| lci.unit}.join(',')              
            end 

            n = 0
            tempfile.each_line do |values|
              add_text_element 'data', values
              n = n + 1
              $stderr.puts "converted #{n} lines to WITSML" if (verbose && n % 1000 == 0 )
            end
            $stderr.puts "converted a total of #{n} lines to WITSML" if verbose
          end
        end
      ensure
        tempfile.close true
      end
    end
  end
  #return nil if all succeeded, or a problem hash if not
  if bad_units.length == 0
    return nil
  else
    e = ConversionError.new bad_units
    raise e
  end
end

#not_empty(s) ⇒ Object



87
88
89
# File 'lib/witsml_file.rb', line 87

def not_empty s
  s && s.length > 0
end