further development on the reassessment routines for PILOT data

This commit is contained in:
Sebastian Wehling-Benatelli 2016-05-03 08:46:13 +02:00
parent ec42e1bd15
commit 210d39882d
9 changed files with 208 additions and 150 deletions

View File

@ -43,7 +43,7 @@ from obspy import UTCDateTime
from pylot.core.io.data import Data
from pylot.core.io.inputs import FilterOptions, AutoPickParameter
from pylot.core.pick.autopick import autopickevent
from pylot.core.io.phases import picks_from_evt
from pylot.core.io.phases import picks_to_dict
from pylot.core.loc.nll import locate as locateNll
from pylot.core.util.defaults import FILTERDEFAULTS, COMPNAME_MAP,\
AUTOMATIC_DEFAULTS
@ -735,7 +735,7 @@ class MainWindow(QMainWindow):
return rval
def updatePicks(self, type='manual'):
picks = picks_from_evt(evt=self.getData().getEvtData())
picks = picks_to_dict(evt=self.getData().getEvtData())
if type == 'manual':
self.picks.update(picks)
elif type == 'auto':

View File

@ -55,15 +55,15 @@ def autoPyLoT(inputfile):
# getting information on data structure
if parameter.hasParam('datastructure'):
datastructure = DATASTRUCTURE[parameter.getParam('datastructure')]()
dsfields = {'root': parameter.getParam('rootpath'),
'dpath': parameter.getParam('datapath'),
'dbase': parameter.getParam('database')}
datastructure = DATASTRUCTURE[parameter.get('datastructure')]()
dsfields = {'root': parameter.get('rootpath'),
'dpath': parameter.get('datapath'),
'dbase': parameter.get('database')}
exf = ['root', 'dpath', 'dbase']
if parameter.hasParam('eventID'):
dsfields['eventID'] = parameter.getParam('eventID')
dsfields['eventID'] = parameter.get('eventID')
exf.append('eventID')
datastructure.modifyFields(**dsfields)
@ -73,20 +73,20 @@ def autoPyLoT(inputfile):
if parameter.hasParam('nllocbin'):
locflag = 1
# get NLLoc-root path
nllocroot = parameter.getParam('nllocroot')
nllocroot = parameter.get('nllocroot')
# get path to NLLoc executable
nllocbin = parameter.getParam('nllocbin')
nllocbin = parameter.get('nllocbin')
nlloccall = '%s/NLLoc' % nllocbin
# get name of phase file
phasef = parameter.getParam('phasefile')
phasef = parameter.get('phasefile')
phasefile = '%s/obs/%s' % (nllocroot, phasef)
# get name of NLLoc-control file
ctrf = parameter.getParam('ctrfile')
ctrf = parameter.get('ctrfile')
ctrfile = '%s/run/%s' % (nllocroot, ctrf)
# pattern of NLLoc ttimes from location grid
ttpat = parameter.getParam('ttpatter')
ttpat = parameter.get('ttpatter')
# pattern of NLLoc-output file
nllocoutpatter = parameter.getParam('outpatter')
nllocoutpatter = parameter.get('outpatter')
maxnumit = 3 # maximum number of iterations for re-picking
else:
locflag = 0
@ -140,10 +140,10 @@ def autoPyLoT(inputfile):
# get latest NLLoc-location file if several are available
nllocfile = max(glob.glob(locsearch), key=os.path.getctime)
# calculating seismic moment Mo and moment magnitude Mw
finalpicks = M0Mw(wfdat, None, None, parameter.getParam('iplot'), \
nllocfile, picks, parameter.getParam('rho'), \
parameter.getParam('vp'), parameter.getParam('Qp'), \
parameter.getParam('invdir'))
finalpicks = M0Mw(wfdat, None, None, parameter.get('iplot'), \
nllocfile, picks, parameter.get('rho'), \
parameter.get('vp'), parameter.get('Qp'), \
parameter.get('invdir'))
else:
print("autoPyLoT: No NLLoc-location file available!")
print("No source parameter estimation possible!")
@ -182,10 +182,10 @@ def autoPyLoT(inputfile):
nlloccounter = maxnumit
# calculating seismic moment Mo and moment magnitude Mw
finalpicks = M0Mw(wfdat, None, None, parameter.getParam('iplot'), \
nllocfile, picks, parameter.getParam('rho'), \
parameter.getParam('vp'), parameter.getParam('Qp'), \
parameter.getParam('invdir'))
finalpicks = M0Mw(wfdat, None, None, parameter.get('iplot'), \
nllocfile, picks, parameter.get('rho'), \
parameter.get('vp'), parameter.get('Qp'), \
parameter.get('invdir'))
# get network moment magntiude
netMw = []
for key in finalpicks.getpicdic():
@ -222,8 +222,8 @@ def autoPyLoT(inputfile):
# single event processing
else:
data.setWFData(glob.glob(os.path.join(datapath, parameter.getParam('eventID'), '*')))
print("Working on event {0}".format(parameter.getParam('eventID')))
data.setWFData(glob.glob(os.path.join(datapath, parameter.get('eventID'), '*')))
print("Working on event {0}".format(parameter.get('eventID')))
print(data)
wfdat = data.getWFData() # all available streams
@ -238,7 +238,7 @@ def autoPyLoT(inputfile):
picksExport(picks, 'NLLoc', phasefile)
# For locating the event the NLLoc-control file has to be modified!
nllocout = '%s_%s' % (parameter.getParam('eventID'), nllocoutpatter)
nllocout = '%s_%s' % (parameter.get('eventID'), nllocoutpatter)
# create comment line for NLLoc-control file
modifyInputFile(ctrf, nllocroot, nllocout, phasef, ttpat)
@ -261,10 +261,10 @@ def autoPyLoT(inputfile):
# get latest NLLOc-location file if several are available
nllocfile = max(glob.glob(locsearch), key=os.path.getctime)
# calculating seismic moment Mo and moment magnitude Mw
finalpicks = M0Mw(wfdat, None, None, parameter.getParam('iplot'), \
nllocfile, picks, parameter.getParam('rho'), \
parameter.getParam('vp'), parameter.getParam('Qp'), \
parameter.getParam('invdir'))
finalpicks = M0Mw(wfdat, None, None, parameter.get('iplot'), \
nllocfile, picks, parameter.get('rho'), \
parameter.get('vp'), parameter.get('Qp'), \
parameter.get('invdir'))
else:
print("autoPyLoT: No NLLoc-location file available!")
print("No source parameter estimation possible!")
@ -303,10 +303,10 @@ def autoPyLoT(inputfile):
nlloccounter = maxnumit
# calculating seismic moment Mo and moment magnitude Mw
finalpicks = M0Mw(wfdat, None, None, parameter.getParam('iplot'), \
nllocfile, picks, parameter.getParam('rho'), \
parameter.getParam('vp'), parameter.getParam('Qp'), \
parameter.getParam('invdir'))
finalpicks = M0Mw(wfdat, None, None, parameter.get('iplot'), \
nllocfile, picks, parameter.get('rho'), \
parameter.get('vp'), parameter.get('Qp'), \
parameter.get('invdir'))
# get network moment magntiude
netMw = []
for key in finalpicks.getpicdic():
@ -319,7 +319,7 @@ def autoPyLoT(inputfile):
##########################################################
# write phase files for various location routines
# HYPO71
hypo71file = '%s/%s/autoPyLoT_HYPO71.pha' % (datapath, parameter.getParam('eventID'))
hypo71file = '%s/%s/autoPyLoT_HYPO71.pha' % (datapath, parameter.get('eventID'))
if hasattr(finalpicks, 'getpicdic'):
if finalpicks.getpicdic() is not None:
writephases(finalpicks.getpicdic(), 'HYPO71', hypo71file)
@ -330,13 +330,13 @@ def autoPyLoT(inputfile):
else:
writephases(picks, 'HYPO71', hypo71file)
data.applyEVTData(picks)
fnqml = '%s/%s/autoPyLoT' % (datapath, parameter.getParam('eventID'))
fnqml = '%s/%s/autoPyLoT' % (datapath, parameter.get('eventID'))
data.exportEvent(fnqml)
endsplash = '''------------------------------------------\n'
-----Finished event %s!-----\n'
------------------------------------------'''.format \
(version=_getVersionString()) % parameter.getParam('eventID')
(version=_getVersionString()) % parameter.get('eventID')
print(endsplash)
if locflag == 0:
print("autoPyLoT was running in non-location mode!")

View File

@ -3,13 +3,13 @@
import os
import glob
import warnings
from obspy.io.xseed import Parser
from obspy.core import read, Stream, UTCDateTime
from obspy import read_events, read_inventory
from obspy.core.event import Event, ResourceIdentifier, Pick, WaveformStreamID
from pylot.core.io.phases import readPILOTEvent
from pylot.core.io.phases import readPILOTEvent, picks_from_dict
from pylot.core.util.utils import fnConstructor, getGlobalTimes
from pylot.core.util.errors import FormatError, OverwriteError
@ -414,35 +414,8 @@ class Data(object):
firstonset = None
if self.getEvtData().picks:
raise OverwriteError('Actual picks would be overwritten!')
for station, onsets in picks.items():
print('Reading picks on station %s' % station)
for label, phase in onsets.items():
if not isinstance(phase, dict):
continue
onset = phase['mpp']
epp = phase['epp']
lpp = phase['lpp']
error = phase['spe']
try:
picker = phase['picker']
except KeyError as e:
warnings.warn(str(e), Warning)
picker = 'Unknown'
pick = Pick()
pick.time = onset
pick.time_errors.lower_uncertainty = onset - epp
pick.time_errors.upper_uncertainty = lpp - onset
pick.time_errors.uncertainty = error
pick.phase_hint = label
pick.method_id = ResourceIdentifier(id=picker)
pick.waveform_id = WaveformStreamID(station_code=station)
self.getEvtData().picks.append(pick)
try:
polarity = phase['fm']
except KeyError as e:
print('No polarity information found for %s' % phase)
if firstonset is None or firstonset > onset:
firstonset = onset
picks, firstonset = picks_from_dict(picks)
self.getEvtData().picks = picks
if 'smi:local' in self.getID() and firstonset:
fonset_str = firstonset.strftime('%Y_%m_%d_%H_%M_%S')
@ -501,7 +474,7 @@ class GenericDataStructure(object):
if not self.extraAllowed():
kwargs = self.updateNotAllowed(kwargs)
for key, value in kwargs.iteritems():
for key, value in kwargs.items():
key = str(key).lower()
if value is not None:
if type(value) not in (str, int, float):

View File

@ -131,7 +131,7 @@ class AutoPickParameter(object):
return True
return False
def getParam(self, *args):
def get(self, *args):
try:
for param in args:
try:

View File

@ -2,7 +2,8 @@
# -*- coding: utf-8 -*-
import os
import glob
import warnings
import scipy.io as sio
import obspy.core.event as ope
from obspy.core import UTCDateTime
@ -173,7 +174,7 @@ def convert_pilot_times(time_array):
return UTCDateTime(*times)
def picks_from_obs(fn):
def picksdict_from_obs(fn):
picks = dict()
station_name = str()
for line in open(fn, 'r'):
@ -191,7 +192,7 @@ def picks_from_obs(fn):
return picks
def picks_from_evt(evt):
def picks_to_dict(evt):
'''
Takes an Event object and return the pick dictionary commonly used within
PyLoT
@ -228,6 +229,82 @@ def picks_from_evt(evt):
picks[station] = onsets.copy()
return picks
def picks_from_dict(picks):
firstonset = None
for station, onsets in picks.items():
print('Reading picks on station %s' % station)
for label, phase in onsets.items():
if not isinstance(phase, dict):
continue
onset = phase['mpp']
epp = phase['epp']
lpp = phase['lpp']
error = phase['spe']
try:
picker = phase['picker']
except KeyError as e:
warnings.warn(str(e), Warning)
picker = 'Unknown'
pick = ope.Pick()
pick.time = onset
pick.time_errors.lower_uncertainty = onset - epp
pick.time_errors.upper_uncertainty = lpp - onset
pick.time_errors.uncertainty = error
pick.phase_hint = label
pick.method_id = ope.ResourceIdentifier(id=picker)
pick.waveform_id = ope.WaveformStreamID(station_code=station)
try:
polarity = phase['fm']
if polarity == 'U' or '+':
pick.polarity = 'positive'
elif polarity == 'D' or '-':
pick.polarity = 'negative'
else:
pick.polarity = 'undecidable'
except KeyError as e:
print('No polarity information found for %s' % phase)
if firstonset is None or firstonset > onset:
firstonset = onset
def reassess_pilot_event(root_dir, event_id):
from obspy import read
from pylot.core.util.defaults import AUTOMATIC_DEFAULTS
from pylot.core.io.inputs import AutoPickParameter
from pylot.core.pick.utils import earllatepicker
default = AutoPickParameter(AUTOMATIC_DEFAULTS)
search_base = os.path.join(root_dir, event_id)
phases_file = glob.glob(os.path.join(search_base, 'PHASES.mat'))
picks_dict = picks_from_pilot(phases_file)
for station in picks_dict.keys():
fn_pattern = os.path.join(search_base, '{0}*'.format(station))
try:
st = read(fn_pattern)
except TypeError as e:
print(e.message)
st = read(fn_pattern, format='GSE2')
if not st:
raise RuntimeError('no waveform data found for station {station}'.format(station=station))
for phase in picks_dict[station].keys():
try:
mpp = picks_dict[station][phase]['mpp']
except KeyError as e:
print(e.message, station)
continue
epp, lpp, spe = earllatepicker(st,
default.get('nfac{0}'.format(phase)),
default.get('tsnrz' if phase == 'P' else 'tsnrh'),
mpp
)
picks_dict[station][phase] = dict(epp=epp, mpp=mpp, lpp=lpp, spe=spe)
# create Event object for export
evt = ope.Event(resource_id=event_id)
evt.picks = picks_from_dict(picks_dict)
# write phase information to file
evt.write('{0}.xml'.format(event_id), format='QUAKEML')
def writephases(arrivals, fformat, filename):
'''

View File

@ -28,9 +28,9 @@ def autopickevent(data, param):
# get some parameters for quality control from
# parameter input file (usually autoPyLoT.in).
wdttolerance = param.getParam('wdttolerance')
mdttolerance = param.getParam('mdttolerance')
iplot = param.getParam('iplot')
wdttolerance = param.get('wdttolerance')
mdttolerance = param.get('mdttolerance')
iplot = param.get('iplot')
for n in range(len(data)):
station = data[n].stats.station
if station not in stations:
@ -66,60 +66,60 @@ def autopickstation(wfstream, pickparam, verbose=False):
# read your autoPyLoT.in for details!
# special parameters for P picking
algoP = pickparam.getParam('algoP')
iplot = pickparam.getParam('iplot')
pstart = pickparam.getParam('pstart')
pstop = pickparam.getParam('pstop')
thosmw = pickparam.getParam('tlta')
tsnrz = pickparam.getParam('tsnrz')
hosorder = pickparam.getParam('hosorder')
bpz1 = pickparam.getParam('bpz1')
bpz2 = pickparam.getParam('bpz2')
pickwinP = pickparam.getParam('pickwinP')
tsmoothP = pickparam.getParam('tsmoothP')
ausP = pickparam.getParam('ausP')
nfacP = pickparam.getParam('nfacP')
tpred1z = pickparam.getParam('tpred1z')
tdet1z = pickparam.getParam('tdet1z')
Parorder = pickparam.getParam('Parorder')
addnoise = pickparam.getParam('addnoise')
Precalcwin = pickparam.getParam('Precalcwin')
minAICPslope = pickparam.getParam('minAICPslope')
minAICPSNR = pickparam.getParam('minAICPSNR')
timeerrorsP = pickparam.getParam('timeerrorsP')
algoP = pickparam.get('algoP')
iplot = pickparam.get('iplot')
pstart = pickparam.get('pstart')
pstop = pickparam.get('pstop')
thosmw = pickparam.get('tlta')
tsnrz = pickparam.get('tsnrz')
hosorder = pickparam.get('hosorder')
bpz1 = pickparam.get('bpz1')
bpz2 = pickparam.get('bpz2')
pickwinP = pickparam.get('pickwinP')
tsmoothP = pickparam.get('tsmoothP')
ausP = pickparam.get('ausP')
nfacP = pickparam.get('nfacP')
tpred1z = pickparam.get('tpred1z')
tdet1z = pickparam.get('tdet1z')
Parorder = pickparam.get('Parorder')
addnoise = pickparam.get('addnoise')
Precalcwin = pickparam.get('Precalcwin')
minAICPslope = pickparam.get('minAICPslope')
minAICPSNR = pickparam.get('minAICPSNR')
timeerrorsP = pickparam.get('timeerrorsP')
# special parameters for S picking
algoS = pickparam.getParam('algoS')
sstart = pickparam.getParam('sstart')
sstop = pickparam.getParam('sstop')
bph1 = pickparam.getParam('bph1')
bph2 = pickparam.getParam('bph2')
tsnrh = pickparam.getParam('tsnrh')
pickwinS = pickparam.getParam('pickwinS')
tpred1h = pickparam.getParam('tpred1h')
tdet1h = pickparam.getParam('tdet1h')
tpred2h = pickparam.getParam('tpred2h')
tdet2h = pickparam.getParam('tdet2h')
Sarorder = pickparam.getParam('Sarorder')
aictsmoothS = pickparam.getParam('aictsmoothS')
tsmoothS = pickparam.getParam('tsmoothS')
ausS = pickparam.getParam('ausS')
minAICSslope = pickparam.getParam('minAICSslope')
minAICSSNR = pickparam.getParam('minAICSSNR')
Srecalcwin = pickparam.getParam('Srecalcwin')
nfacS = pickparam.getParam('nfacS')
timeerrorsS = pickparam.getParam('timeerrorsS')
algoS = pickparam.get('algoS')
sstart = pickparam.get('sstart')
sstop = pickparam.get('sstop')
bph1 = pickparam.get('bph1')
bph2 = pickparam.get('bph2')
tsnrh = pickparam.get('tsnrh')
pickwinS = pickparam.get('pickwinS')
tpred1h = pickparam.get('tpred1h')
tdet1h = pickparam.get('tdet1h')
tpred2h = pickparam.get('tpred2h')
tdet2h = pickparam.get('tdet2h')
Sarorder = pickparam.get('Sarorder')
aictsmoothS = pickparam.get('aictsmoothS')
tsmoothS = pickparam.get('tsmoothS')
ausS = pickparam.get('ausS')
minAICSslope = pickparam.get('minAICSslope')
minAICSSNR = pickparam.get('minAICSSNR')
Srecalcwin = pickparam.get('Srecalcwin')
nfacS = pickparam.get('nfacS')
timeerrorsS = pickparam.get('timeerrorsS')
# parameters for first-motion determination
minFMSNR = pickparam.getParam('minFMSNR')
fmpickwin = pickparam.getParam('fmpickwin')
minfmweight = pickparam.getParam('minfmweight')
minFMSNR = pickparam.get('minFMSNR')
fmpickwin = pickparam.get('fmpickwin')
minfmweight = pickparam.get('minfmweight')
# parameters for checking signal length
minsiglength = pickparam.getParam('minsiglength')
minpercent = pickparam.getParam('minpercent')
nfacsl = pickparam.getParam('noisefactor')
minsiglength = pickparam.get('minsiglength')
minpercent = pickparam.get('minpercent')
nfacsl = pickparam.get('noisefactor')
# parameter to check for spuriously picked S onset
zfac = pickparam.getParam('zfac')
zfac = pickparam.get('zfac')
# path to inventory-, dataless- or resp-files
invdir = pickparam.getParam('invdir')
invdir = pickparam.get('invdir')
# initialize output
Pweight = 4 # weight for P onset
@ -857,39 +857,39 @@ def iteratepicker(wf, NLLocfile, picks, badpicks, pickparameter):
wf2pick = wf.select(station=badpicks[i][0])
# modify some picking parameters
pstart_old = pickparameter.getParam('pstart')
pstop_old = pickparameter.getParam('pstop')
sstop_old = pickparameter.getParam('sstop')
pickwinP_old = pickparameter.getParam('pickwinP')
Precalcwin_old = pickparameter.getParam('Precalcwin')
noisefactor_old = pickparameter.getParam('noisefactor')
zfac_old = pickparameter.getParam('zfac')
pstart_old = pickparameter.get('pstart')
pstop_old = pickparameter.get('pstop')
sstop_old = pickparameter.get('sstop')
pickwinP_old = pickparameter.get('pickwinP')
Precalcwin_old = pickparameter.get('Precalcwin')
noisefactor_old = pickparameter.get('noisefactor')
zfac_old = pickparameter.get('zfac')
pickparameter.setParam(
pstart=max([0, badpicks[i][1] - wf2pick[0].stats.starttime \
- pickparameter.getParam('tlta')]))
pickparameter.setParam(pstop=pickparameter.getParam('pstart') + \
(3 * pickparameter.getParam('tlta')))
pickparameter.setParam(sstop=pickparameter.getParam('sstop') / 2)
pickparameter.setParam(pickwinP=pickparameter.getParam('pickwinP') / 2)
- pickparameter.get('tlta')]))
pickparameter.setParam(pstop=pickparameter.get('pstart') + \
(3 * pickparameter.get('tlta')))
pickparameter.setParam(sstop=pickparameter.get('sstop') / 2)
pickparameter.setParam(pickwinP=pickparameter.get('pickwinP') / 2)
pickparameter.setParam(
Precalcwin=pickparameter.getParam('Precalcwin') / 2)
Precalcwin=pickparameter.get('Precalcwin') / 2)
pickparameter.setParam(noisefactor=1.0)
pickparameter.setParam(zfac=1.0)
print(
"iteratepicker: The following picking parameters have been modified for iterative picking:")
print(
"pstart: %fs => %fs" % (pstart_old, pickparameter.getParam('pstart')))
"pstart: %fs => %fs" % (pstart_old, pickparameter.get('pstart')))
print(
"pstop: %fs => %fs" % (pstop_old, pickparameter.getParam('pstop')))
"pstop: %fs => %fs" % (pstop_old, pickparameter.get('pstop')))
print(
"sstop: %fs => %fs" % (sstop_old, pickparameter.getParam('sstop')))
"sstop: %fs => %fs" % (sstop_old, pickparameter.get('sstop')))
print("pickwinP: %fs => %fs" % (
pickwinP_old, pickparameter.getParam('pickwinP')))
pickwinP_old, pickparameter.get('pickwinP')))
print("Precalcwin: %fs => %fs" % (
Precalcwin_old, pickparameter.getParam('Precalcwin')))
Precalcwin_old, pickparameter.get('Precalcwin')))
print("noisefactor: %f => %f" % (
noisefactor_old, pickparameter.getParam('noisefactor')))
print("zfac: %f => %f" % (zfac_old, pickparameter.getParam('zfac')))
noisefactor_old, pickparameter.get('noisefactor')))
print("zfac: %f => %f" % (zfac_old, pickparameter.get('zfac')))
# repick station
newpicks = autopickstation(wf2pick, pickparameter)

View File

@ -9,7 +9,7 @@ import matplotlib.pyplot as plt
from obspy import read_events
from pylot.core.io.phases import picks_from_evt
from pylot.core.io.phases import picks_to_dict
from pylot.core.util.pdf import ProbabilityDensityFunction
from pylot.core.util.version import get_git_version as _getVersionString
@ -227,7 +227,7 @@ class PDFDictionary(object):
if len(cat) > 1:
raise NotImplementedError('reading more than one event at the same '
'time is not implemented yet! Sorry!')
return PDFDictionary(picks_from_evt(cat[0]))
return PDFDictionary(picks_to_dict(cat[0]))
def pdf_data(self, type='exp'):
"""

View File

@ -3,16 +3,21 @@
import argparse
from pylot.core.util.version import get_git_version as _getVersionString
from pylot.core.io.phases import reasses_pilot_event
from pylot.core.io.phases import reassess_pilot_event
__version__ = _getVersionString()
__author__ = 'sebastianw'
def reassess_pilot_event():
pass
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument(
'--directory', '-d', type=str, help='specifies the root directory (in '
'most cases PILOT database folder)'
)
parser.add_argument(
'--eventid', '-i', type=str, help='PILOT event identifier'
)
args = parser.parse_args()
reasses_pilot_event(args.id)
reassess_pilot_event(args.dir, args.id)

View File

@ -1,3 +1,5 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from distutils.core import setup
setup(
@ -6,6 +8,7 @@ setup(
packages=['pylot', 'pylot.core', 'pylot.core.loc', 'pylot.core.pick',
'pylot.core.io', 'pylot.core.util', 'pylot.core.active',
'pylot.core.analysis', 'pylot.testing'],
requires=['obspy', 'PySide'],
url='dummy',
license='LGPLv3',
author='Sebastian Wehling-Benatelli',