Following a very old post (link), and questions from Matthias and Kevin, I’ve finally managed to test the R2-related scripts I wrote long-long time ago…
I’m really sorry, but don’t quite have the time now to really document all functions/actions, but it should be quite straightforward. This script assumes you start from a ABEM S4K file, or with a ABEM AMP file converted using the command ‘s 4kconv.exe -F:a -z0 -x myinputfile.s4k’. If you have the S4K file, you should be able to convert is on the fly with the script (look for the “convert=False” flag). There are no fancy python imports, except the classic trio: numpy, scipy and matplotlib.
NOTE: there seems to be a problem with the os.spawnl() call to R2.exe within the code, I don’t quite know why for now. So, to run the test, I simply launched R2.exe in console and re-ran the python script to plot the results.
The ouptut of the test case should look like :
The scripts, thus, expects :
- a data folder with
- a .S4K of .AMP file
- a .wgs84 file, N lines of ‘LON LAT ALT’, 1 per electrode
- R2.exe
- if you need to convert, a folder with the s4kconv.exe program
This code should really be improved to be more “dynamic”, if you edit/modify/improve it, please report back and I’ll update/add your contribution to this blog.
The full code and the example data files are present after the break !
The following files should be placed under a /data folder (and remember to copy the R2.exe to this folder too): data.rar
The full code is:
#
import os
import datetime
import sys
from numpy import *
from matplotlib.pyplot import plot, show, scatter
class ResistivityData:
def __init__(self):
self.title = ''
def ParseAMP(self, file):
file = file[:-3] + 'AMP'
f = open(file,'r')
datalines = f.readlines()
f.close()
self.basefolder = os.path.split(file)[0]
# read header
file = os.path.basename(datalines[0].split(":",1)[1].strip())
instrument_model, instrument_serial = datalines[1].split(":",1)[1].strip().split()
date, time = datalines[2].split(":",1)[1].strip().split()
day, month, year = [int(str) for str in date.split("/")]
hours, mins, secs = [int(str) for str in time.split(":")]
# date and time is sometimes completely off
try:
date_time = datetime.datetime(year, month, day, hours, mins, secs)
except ValueError:
print "Warning: date and/or time out of range!"
S4Kfile = AMPfile[:-4] + '.S4K'
if os.path.exists(S4Kfile):
print "Using ctime of file %s" % S4Kfile
ctime = os.path.getctime(S4Kfile)
else:
print "Using ctime of file %s" % AMPfile
ctime = os.path.getctime(AMPfile)
date_time = datetime.datetime.fromtimestamp(ctime)
basestation_coords = datalines[3].split(":",1)[1].strip().split()
header_rows, data_rows, topo_rows = [int(w) for w in datalines[4].split(":",1)[1].strip().split()]
acquisition_mode = datalines[5].split(":",1)[1].strip()
method = datalines[6].split(":",1)[1].strip()
electrode_layout = int(datalines[7].split(":",1)[1].strip().split()[0])
coordinate_type = datalines[8].split(":",1)[1].strip()
dE = float(datalines[9].split(":",1)[1].strip())
self.dE = dE
PPlus = []
PMinus = []
CPlus = []
CMinus = []
Resist = []
for i, line in enumerate(datalines[27:]):
no, time, ax, ay, az, bx, by, bz, mx, my, mz, nx, ny, nz, i, v, r, error = line.split()
# print no, int(ax)+32, int(bx)+32, int(mx)+32, int(nx)+32, i, v, r, error
p_plus = int(mx)+32
p_minus = int(nx)+32
c_plus = int(ax)+32
c_minus = int(bx)+32
r = float(r)
PPlus.append(p_plus)
PMinus.append(p_minus)
CPlus.append(c_plus)
CMinus.append(c_minus)
Resist.append(r)
# print no, p_plus, p_minus, c_plus, c_minus, r
self.PPlus = PPlus
self.PMinus = PMinus
self.CPlus = CPlus
self.CMinus = CMinus
self.Resist = Resist
def create_mesh(self):
electrode_spacing = self.dE
max_depth = 40.0
layers_thickness = 1.0
mesh_X_increment = electrode_spacing / self.split_factor
### MESH GENERATION :
borders = array([1,1,1,1,1,1,1,2,4,5,10,25,50])
# print sum(borders)
before = borders[::-1]*mesh_X_increment
# print before
after = borders*mesh_X_increment
# print after
central = ones((self.num_electrodes*self.split_factor)+1-self.split_factor-1)*mesh_X_increment
# print 'len central', len(central)
# print 'central', central
tempX = hstack((before,central,after[:-1]))
# print 'len tempX', len(tempX)
# print 'tempX', tempX
old_value = -103.0 * mesh_X_increment # TO CHANGE !!
meshX = []
for value in tempX:
old_value += value
meshX.append(old_value)
# print len(meshX), meshX
bottom = array([2,2,2,2,2,2,2,2,4,8,10,20,50,100])
depth = ones(max_depth / layers_thickness)
tempY = hstack((depth,bottom))
old_value = 0.0
meshY = [old_value,]
for value in tempY:
old_value += value
meshY.append(old_value)
topog = zeros(len(meshX))
num_of_elements = (len(meshX)-1)*(len(meshY)-1)
self.meshX = meshX
self.meshY = meshY
self.topog = topog
self.num_of_elements = num_of_elements
def export_R2in(self):
output = os.path.join(self.basefolder,'R2.in')
output = open(output,'w')
num_electrodes = self.num_electrodes
split_factor = self.split_factor
output.write("Header generated\n")
output.write("\n")
output.write(" 1 4 3.0 0 1\n")
output.write("\n")
output.write(" %i %i << numnp_x, numnp_y\n" % (len(self.meshX),len(self.meshY)))
output.write("\n")
out = ""
for i, value in enumerate(self.meshX):
if i % 15 == 0:
output.write("%s\n"% out)
out = ""
out += "%f\t"%value
output.write("%s\n"% out)
output.write("\n")
out = ""
for i, value in enumerate(self.topog):
if i % 15 == 0:
output.write("%s\n"% out)
out = ""
out += "%f\t"%value
output.write("%s\n"% out)
output.write("\n")
out = ""
for i, value in enumerate(self.meshY):
if i % 15 == 0:
output.write("%s\n"% out)
out = ""
out += "%f\t"%value
output.write("%s\n"% out)
output.write("""
1 << num_regions
1 %i 100.000 << elem_1,elem_2,value
1 1 << no. patches in x, no. patches in z
1 << inverse_type
1 0 << data type (0=normal;1=log), regularization type
1.0 10 2 1.0 << tolerance, max_iterations, error_mod, alpha_aniso
0.00100 0.02000 -10000.0 10000.0 << a_wgt, b_wgt, rho_min, rho_max
""" % (self.num_of_elements))
electrode_indexes = linspace(0,num_electrodes*split_factor,num_electrodes+1)
electrode_indexes += 13 + split_factor
output.write(" %i << num_electrodes\n" % (num_electrodes))
for i, value in enumerate(electrode_indexes[:-1]):
output.write("%i\t%i\t%i\n" % (i+1, value, 1))
def export_R2Protocoldat(self):
output = os.path.join(self.basefolder,"protocol.dat")
output = open(output,'w')
output.write("%i\n" % len(self.Resist))
i = 1
for P,p,C,c,r in zip(self.PPlus,self.PMinus,self.CPlus,self.CMinus,self.Resist):
output.write("%i\t%i\t%i\t%i\t%i\t%f\n" % (i, P,p,C,c,r))
i+=1
def add_topo(self,file=None):
if file:
f = open(file,'r')
lines = f.readlines()
f.close()
Z = []
for line in lines:
# ID, x, y, z = line.split()
x, y, z = line.split()
z = float(z)
Z.append(z)
x_old = linspace(1.,self.num_electrodes, self.num_electrodes)
x_new = linspace(1.,self.num_electrodes, (self.num_electrodes*self.split_factor)+1-self.split_factor-1)
if file:
Z = array(Z)
Z_new = interp(x_new,x_old,Z)
else:
Z_new = ones(len(x_new))*100.
before = linspace(Z_new[0],Z_new[0],13)
after = linspace(Z_new[-1],Z_new[-1],12)
Z_new = hstack((before,Z_new, after))
before = linspace(-12,0,13)
after = linspace(self.num_electrodes+1,self.num_electrodes+13, 13)
x_new = hstack((before, x_new, after))
self.topog = Z_new
class R2_Data:
def __init__(self, num_electrodes, split_factor, dE):
self.num_electrodes = num_electrodes
self.split_factor = split_factor
self.dE = dE
self.title = ''
def extract_topo(self, xin, yin, Rin,Show=False):
#EXTRACT THE TOPOGRAPHY, hence THE Max yin for each xin
last_xi = 9999
Yi = []
Xi = []
for xi,yi in zip(xin,yin):
if xi != last_xi:
Yi.append(yi)
Xi.append(xi)
last_xi = xi
topoy = array(Yi)
topox = array(Xi)
if Show:
plt.scatter(xin,yin,marker='+')
plt.scatter(topox,topoy)
plt.grid(True)
show()
return topox, topoy
def read_result(self,filename=None,title='UnNamedProfile',maxdepth=None):
if filename:
input = filename
else:
input = os.path.join(self.basefolder,"f001_res.dat")
if not maxdepth:
maxdepth = 40
input = open(input,'r')
lines = input.readlines()
input.close()
xin = []
yin = []
Rin = []
for line in lines:
x,y,r,logr = line[:-1].split()
xin.append(float(x))
yin.append(float(y))
Rin.append(float(logr))
from matplotlib.mlab import griddata
from numpy import linspace
from scipy import arange, array, meshgrid, ma
from matplotlib import cm
import matplotlib.pyplot as plt
xin = array(xin)
yin = array(yin)
Rin = array(Rin)
topox, topoy = self.extract_topo(xin, yin, Rin)
xi = linspace(0.,(self.num_electrodes-1)*self.dE,250)
# testing
ymax = max(topoy)
ymin = min(topoy) - maxdepth
yi = linspace(ymin,ymax,maxdepth+1)
xi2, yi2 = meshgrid(xi,yi)
print 'yin', yin
zi = griddata(xin,yin,Rin,xi2,yi2)
print 'zi',zi
extent = (min(xi),max(xi),min(yi),max(yi))
plt.figure()
ax = plt.subplot(111,aspect=2.5)
sc = plt.imshow(zi, cmap=cm.jet,interpolation='bicubic',origin='lower',extent=extent,zorder=-10)
cs = plt.contour(zi,origin='lower',extent=extent,colors='k',linewidths=0.25,antialiased=True,zorder=-5)
plt.clabel(cs, fontsize=4, inline=1,fmt='%.1f')
# print ax.get_units()
x1 = topox[11:-11]
y1 = topoy[11:-11]
y2 = ones(len(topoy[11:-11]))*max(topoy)
plt.fill_between(x1,y1+.05,y2,color='w',zorder=10)
plt.fill_between(x1,y1-maxdepth-.5,color='w',zorder=-1,alpha=0.8)
cb = plt.colorbar(sc, orientation="horizontal", spacing="uniform", format="%.1f",aspect=40,shrink=0.75)
cb.set_label('log10(Resistivity (ohm.m))',fontsize=7)
# plt.plot(linspace(0,max(xi),len(self.topog[13:-13])),self.topog[13:-13],'k-')
plt.plot(x1,y1,'k-',zorder=60)
for t in cb.ax.get_xticklabels():
t.set_fontsize(6)
if self.title == '':
self.title = "Profile: " + title
plt.title(self.title,fontsize=10, style='italic', weight='bold')
plt.xticks(fontsize=5)
plt.yticks(fontsize=5)
plt.ylabel('Elevation (m)',fontsize=7)
plt.xlabel('Distance (m)',fontsize=7)
filename = os.path.join(self.basefolder,title + '.R2.PNG')
plt.grid(color='k',linestyle=':',linewidth=0.3,alpha=0.9,zorder=2)
plt.xlim(0,(self.num_electrodes-1)*self.dE)
plt.ylim(min(yi),max(yi)+5)
# plt.savefig(filename,dpi=200,orientation='landscape',papertype='a4')
plt.savefig(filename,dpi=200)
plt.show()
# plt.clf()
def s4kconv(s4kfile):
"""
Wrapper for SAS4000 S4KCONV program (DOS!)
"""
"""
# convert path to DOS path using cygwin
cmd = r'cygpath -d "%s"' % s4kfile.replace('\\', '/')
stdin, stdout = os.popen2(cmd, 't')
stdin.write('\n')
stdin.close()
dos_s4kfile = stdout.readline()
dos_s4kfile = dos_s4kfile.strip()
stdout.close()
# convert program path to DOS as well
cmd = r'cygpath -d "%s"' % os.path.join(SAS4000_DIR, "s4kconv.exe").replace('\\', '/')
stdin, stdout = os.popen2(cmd, 't')
stdin.write('\n')
stdin.close()
dos_s4kconv_path = stdout.readline()
dos_s4kconv_path = dos_s4kconv_path.strip()
stdout.close()
"""
## SAS4000 path
SAS4000_DIR = os.path.abspath("./SAS4000")
PROTOCOL_DIR = os.path.join(SAS4000_DIR, "C2P2")
dos_s4kfile = s4kfile
dos_ampfile = dos_s4kfile[:-4] + ".AMP"
if os.path.exists(dos_ampfile):
os.unlink(dos_ampfile)
dos_s4kconv_path = os.path.join(SAS4000_DIR, "s4kconv.exe")
#args = r'%s %s %s' % (dos_s4kconv_path, '-F:a', dos_s4kfile)
#os.spawnle(os.P_WAIT, os.path.join(SAS4000_DIR, "s4kconv"), args, os.environ)
os.spawnl(os.P_WAIT, os.path.join(SAS4000_DIR, "s4kconv.exe"), dos_s4kconv_path, '-F:a -z0 -x', dos_s4kfile)
tmpfile = dos_ampfile[:-4] + ".TMP"
ampfile = s4kfile[:-4] + ".AMP"
os.rename(dos_ampfile, tmpfile)
fin = open(tmpfile, 'r')
fout = open(ampfile, 'w')
lines = fin.readlines()
fin.close()
fout.write("Filename: %s\n" % os.path.split(s4kfile)[1])
for line in lines[1:]:
fout.write(line)
fout.close()
os.unlink(tmpfile)
def test_run():
# file = r"c:\Vecquee01.s4k"
file = os.path.abspath(r"data\20090806-1.AMP")
# title = 'Crossing Railway - 2009-08-20'
title = '20090806-1'
has_topo = True
work_on_AMP = True
convert = False
run = True
num_electrodes = 128
split_factor = 1.0
dE = 5
if work_on_AMP and convert:
s4kconv(file)
data = ResistivityData()
data.num_electrodes = num_electrodes
data.split_factor = split_factor
data.dE = dE
if work_on_AMP:
data.ParseAMP(file)
else:
# you have to define the arrays by providing the values :
# data.CMinus = array()
# data.CPlus = array()
# data.PMinus = array()
# data.PPlus = array()
# data.Resist = array()
pass
data.create_mesh() #is based on the topo file
if has_topo:
topo_file = file[:-3] + 'wgs84'
data.add_topo(topo_file)
data.export_R2Protocoldat()
data.export_R2in()
print "AT THIS POINT ; LAUNCH R2.EXE IN THE DATA FOLDER, THEN RERUN THIS SCRIPT TO PLOT THE RESULT"
# if run:
# os.chdir(os.path.split(file)[0])
# print os.path.join(os.path.split(file)[0],'R2.exe')
# os.spawnl(os.P_WAIT, os.path.join(os.path.split(file)[0],'R2.exe'))
Result = R2_Data(num_electrodes=num_electrodes,split_factor=split_factor,dE=dE)
if work_on_AMP:
Result.basefolder = data.basefolder
Result.read_result(title=title)
else:
#Result.read_result(filename="PATH_TO_ANOTHER_FILE",title=title)
pass
if __name__ == "__main__":
test_run()

Hey Thanks!
this gives a great starting point for our workflow using R2
My pleasure ! (btw I’m interested in the workflow !)
Hello!
I am wondering to write such program I’m Matlab, but I dont understand what kind of data I should use for that, having dat file from field data only.
Can you help me?
Hi,
No, I can’t help. First, I use only matlab when I need to translate code to Python, this program is fairly simple, but I’d suggest you go ahead and learn python, it’s much more fun ! Good luck !
One More question, please!
Do you use inversion in this program!? Is it least square inversion?
Griddata interpolation was used here, but how can you evaluate the inversion results?