Migration guide 0.3 SDK¶
This is a guide to help migrating from SDK version 0.2.X to 0.3. This guide assumes that the code to be migrated is using the v1 API of the 0.2.X SDK. Refer to the v0 to v1 migration guide if the code is using the v0 API.
Overview¶
All v0 APIs have been removed. As a consequence, some V1 APIs have been renamed.
SDK | 0.2 | 0.3 |
---|---|---|
Survey | survey /survey_v1 |
survey |
File | file /file_seismic |
file |
Volume | volume_seismic |
trace |
Seismic store | seismicstore |
seismicstore |
Seismic | seismic |
seismic |
Job | job |
job |
Partition | partition |
partition |
Search changes¶
The way search parameters are passed to search
methods for seismic store, partitions, and seismics have been changed. Instead of setting the search mode
, a SearchSpec
object that describes the nature of the search is passed to the search methods. For example, a search(mode='seismicstore', name_substring='my-substring')
call will instead be search(search_spec=SearchSpecSeismicStore(name_substring='my-substring'))
. Details can be found in the documentation for each search
method, as well as in the endpoint-by-endpoint guide below.
Identifier changes¶
All methods that previously accepted a string-based id
argument now accept it as uuid
. All methods that require unique identifiers (particularly file
and survey
) now accept external_id
and numeric id
(excluding seismic stores, which do not have external ids). This is to standardize object identifiers with Cognite Data Fusion. While uuid
will continue to be supported, migrating to id
and external_id
is highly recommended.
Seismic 2D support¶
Support for 2D seismic data has been added and is exclusively available via the 0.3 SDK. The SDK has been reworked to accomodate the changes required for 2D seismic, so 2D features are only available via 0.3.
VolumeDef retired¶
VolumeDef
is now a legacy format and is replaced. Line ranges are replaced with extents, and trace counts are replaced with a new trace count endpoint, trace.get_trace_bounds()
. This work is in support of 2D functionality.
Endpoint-by-endpoint guide¶
The following is a comprehensive endpoint-by-endpoint comparison between 0.2 and 0.3 methods.
Client setup¶
[2]:
# Setting up the client
from cognite.seismic import CogniteSeismicClient
base_url="https://greenfield.cognitedata.com"
project="seismic-test"
[8]:
# Key-based auth
import getpass
api_key = getpass.getpass("Enter your Cognite API key: ")
client = CogniteSeismicClient(
api_key=api_key,
base_url=base_url,
project=project
)
[3]:
# OAuth
import msal
tenant_id = "cogniteseismic.onmicrosoft.com"
client_id = "CLIENT ID FOR OIDC"
def login_and_get_token_supplier(base_url):
authority = "https://login.microsoftonline.com/" + tenant_id
app = msal.PublicClientApplication(client_id=client_id, authority=authority)
scopes = [base_url + "/.default"]
app.acquire_token_interactive(scopes=scopes)
try:
account = app.get_accounts()[0]
except IndexError:
raise Exception("No accounts returned after Azure AD login. Check permissions?")
def tokenmaker():
return app.acquire_token_silent(account=account, scopes=scopes)["access_token"]
return tokenmaker
tokenmaker = login_and_get_token_supplier(base_url)
client = CogniteSeismicClient(base_url=base_url, oidc_token=tokenmaker, project=project)
Survey¶
Creating a survey now uses the “create” call. The main difference is that an external_id
must be provided. Additionally, the crs
argument is mandatory.
[3]:
# 0.2
# client.survey.register(survey_name)
# client.survey.get(
# survey_name="my new survey",
# # Can set these to True or False depending on requirements
# list_seismics=True,
# list_seismic_stores=True
# )
# 0.3
client.survey.create(name='my new survey', external_id='my-new-survey', crs='EPSG:4326')
survey = client.survey.get(
external_id='my-new-survey'
)
survey
[3]:
Survey(id=8233797238426673, external_id='my-new-survey', name='my new survey', seismic_ids=[], metadata={})
Getting surveys is largely unchanged. Like in the 0.2 SDK, surveys can be fetched by name or string id. In the latter case, the id should be provided via the uuid
parameter. Surveys can also be fetched by numeric id and external id, and this is the preferred method of identifying surveys.
[4]:
# 0.2
# client.survey_v1.get(survey_name=survey.name)
# client.survey_v1.get(survey_id=survey.uuid)
# 0.3
client.survey.get(name=survey.name)
client.survey.get(uuid=survey.uuid) # Previously "id"
client.survey.get(external_id=survey.external_id)
client.survey.get(id=survey.id) # Numerical internal id
[4]:
Survey(id=8697773075018874, external_id='my-new-survey', name='my new survey', seismic_ids=[], metadata={})
Searching for and editing surveys is also mostly unchanged, aside from the id
/uuid
difference as well as the addition of external_id
and numeric id
.
[6]:
# 0.2
# client.survey_v1.search(name_substring='survey')
#
# client.survey_v1.edit(id=survey.id, crs='EPSG:23031')
# 0.3
client.survey.search(name_substring='survey')
client.survey.search(uuid=survey.uuid) # Was not possible to search by uuid in 0.2
client.survey.edit(id=survey.id, crs='EPSG:23031') # uuid is not supported
[6]:
Survey(id=8233797238426673, external_id='my-new-survey', name='my new survey', seismic_ids=[], metadata={})
Surveys can be only be deleted using (numeric) id
and external_id
. If the id
or external_id
is not known, get
ing the survey and passing survey.id
is recommended.
[ ]:
# 0.2
# client.survey_v1.delete(name=survey.name)
# 0.3
client.survey.delete(external_id=survey.external_id) # uuid and name-based deletion is not supported.
Files¶
File endpoints are mostly unchanged. uuid
s are replaced by id
and external_id
is mandatory, and file_seismic
is replaced by file
.
[ ]:
# 0.2
# client.file_seismic.register(...)
# client.file_seismic.ingest(...)
# client.file_seismic.get(...)
client.file.register(...)
client.file.ingest(...)
client.file.get(...)
Like seismic stores, searches now utilize SearchSpec. Previously, files could only be searched for by file identifiers (id, name, substring). Now files can also be searched for by seismic store or survey identifiers.
[3]:
from cognite.seismic import SearchSpecSurvey, SearchSpecFile, SearchSpecSeismicStore
file_uuid = '99862bf1-9ae6-420e-a40a-5cff134344c3'
file_id = 521798174165669
# 0.2
# client.file.search(id=file_uuid)
# 0.3
client.file.search(search_spec=SearchSpecFile(id=file_id)) # by file identifiers
client.file.search(search_spec=SearchSpecSurvey(name='survey')) # by survey identifiers
client.file.search(search_spec=SearchSpecSeismicStore(id=205818405704076)) # by seismic store identifiers
[3]:
<generator object FileAPI.search.<locals>.<genexpr> at 0x11e7be510>
Partitions¶
Partitions do not have any changes.
Seismic stores¶
Seismic store objects no longer have volume def fields. These are replaced with extents and get_trace_bounds
:
[4]:
# An example seismic store
store_id = 205818405704076
store = client.seismicstore.get(id=store_id)
## Getting i/xline ranges
# 0.2
# store.inline_volume_def.get_inline_range()
# 0.3
# 3d extents are divided into three types:
# - Seismic3dRect: A simple rectangular extent
# - Seismic3dRects: Multiple rectangles
# - Seismic3dDef: A mapping from inline or crossline to, respectively, crossline or inline.
# Simply retrieving bounds is easiest done with the get_trace_bounds endpoint:
bounds = client.traces.get_trace_bounds(seismic_store_id=store_id)
print(f'Bounds: inline {bounds.inline_bounds} crossline {bounds.xline_bounds}\n')
# More detailed analysis can be run directly on extents, which replace VolumeDefs.
# Docs have details on Seismic3dRect/Seismic3dRects/Seismic3dDef
from pprint import pprint
pprint(store.extent)
print()
## Getting trace counts
# 0.2
# store.inline_volume_def.count_total_traces()
# 0.3 using the get_trace_bounds endpoint
print(f'Traces: {client.traces.get_trace_bounds(seismic_store_id=store_id).num_traces}')
Bounds: inline RangeInclusive(1, 5, 1) crossline RangeInclusive(20, 24, 1)
Seismic3dDef(major_header=<TraceHeaderField.INLINE: 3>,
minor_header=<TraceHeaderField.CROSSLINE: 4>,
lines={1: [RangeInclusive(20, 24, 1)],
2: [RangeInclusive(20, 24, 1)],
3: [RangeInclusive(20, 24, 1)],
4: [RangeInclusive(20, 24, 1)],
5: [RangeInclusive(20, 24, 1)]})
Traces: 25
Similar to partitions, seismic store search now utilizes SearchSpec
objects rather than a mode
switch.
[11]:
# 0.2
# client.seismicstore.search(mode='survey', name_substring='sgy')
# client.seismicstore.search(get_all=True)
# 0.3
from cognite.seismic import SearchSpecGetAll, SearchSpecSurvey
client.seismicstore.search(search_spec=SearchSpecSurvey(name_substring='sgy'))
client.seismicstore.search(search_spec=SearchSpecGetAll()) # get_all is removed in favor of a SearchSpec.
[11]:
<generator object SeismicStoreAPI.search at 0x11df092e0>
Seismics¶
Seismics, like seismic stores, use extent
s instead of VolumeDef for describing traces.
[12]:
# 0.2
# An example seismic
seismic_id = 141216751086266
## Getting i/xline ranges
# (Refer to the section on seismic stores)
## Getting trace counts
# 0.2
# store.inline_volume_def.count_total_traces()
# 0.3 using the get_trace_bounds endpoint
print(f'Traces: {client.traces.get_trace_bounds(seismic_id=seismic_id).num_traces}')
Traces: 25
Seismic search uses SearchSpec
s instead of a mode
switch. Like seismic stores, getting all seismics uses SearchSpecGetAll
instead of a get_all
parameter.
[13]:
# 0.2
# client.seismic.search(mode='partition', external_id_substring='my-partition')
# client.seismic.search(get_all=True)
# 0.3
from cognite.seismic import SearchSpecPartition, SearchSpecGetAll
client.seismic.search(search_spec=SearchSpecPartition(external_id_substring='my-partition'))
client.seismic.search(search_spec=SearchSpecGetAll())
[13]:
<generator object SeismicAPI.search at 0x11deee7b0>
Trace data¶
Trace data is now handled through the trace
API and is also available on SeismicStore
and Seismic
objects. Inline/xline access should use Seismic3dRect. It is now also possible to stream multiple rects at once with Seismic3dRects
, and specific traces can be streamed with Seismic3dDef
, similarly to previous VolumeDef
usage.
[4]:
from cognite.seismic import Geometry, Seismic3dRect
crs = 'EPSG:4326'
wkt = 'POLYGON((-1.488209131092365 0,-1.488209131180926 0.0003607712069160569,-1.488567477056032 0.0003607710285892414,-1.4885674769674655 0,-1.488209131092365 0))'
geom = Geometry(crs=crs, wkt=wkt)
seismic_id = 141216751086266
## Getting volumes
# 0.2
# client.volume_seismic.get_volume(id=seismic_id, inline_range=(20, 24), xline_range=(20, 24)) # by line range
# client.volume_seismic.get_volume(id=seismic_id, geometry=geom) # by geometry
# 0.3
client.traces.stream_traces(seismic_id=seismic_id, extent=Seismic3dRect(inline=(20, 24), xline=(20, 24))) # by line range
client.traces.stream_traces(seismic_id=seismic_id, geometry=geom) # by geometry
[4]:
<generator object TracesAPI.stream_traces at 0x11e7be890>
[15]:
# An example seismic store
store_id = 205818405704076
store = client.seismicstore.get(id=store_id)
## Streaming Seg-Y files
# 0.2
# client.file_seismic.get_segy(seismic_store_id=store_id)
# 0.3
client.traces.get_segy(store_id=store_id)
store.get_segy() # Can also use SeismicStore objects directly to stream SegY files
[15]:
<generator object TracesAPI.get_segy at 0x11df36350>