GettingStartedWithOcean 2015
GettingStartedWithOcean 2015
Copyright Notice
Copyright © 2015 Schlumberger. All rights reserved.
This work contains the confidential and proprietary trade secrets of Schlumberger
and may not be copied or stored in an information retrieval system, transferred,
used, distributed, translated or retransmitted in any form or by any means,
electronic or mechanical, in whole or in part, without the express written permission
of the copyright owner.
Security Notice
The software described herein is configured to operate with at least the minimum
specifications set out by Schlumberger. You are advised that such minimum
specifications are merely recommendations and not intended to be limiting to
configurations that may be used to operate the software. Similarly, you are advised
that the software should be operated in a secure environment whether such
software is operated across a network, on a single system and/or on a plurality of
systems. It is up to you to configure and maintain your networks and/or system(s) in
a secure manner. If you have further questions as to recommendations regarding
recommended specifications or security, please feel free to contact your local
Schlumberger representative.
Welcome to Ocean for Petrel
Table of Contents
Welcome to Ocean for Petrel ................................................................ 5
Ocean Architecture ................................................................................................ 5
Access to the Petrel Data Domain .......................................................................... 6
Ocean for Petrel UI Infrastructure ......................................................................... 6
The Ocean Plug-in and Module .............................................................................. 7
Plugin class..................................................................................................... 8
IModule Interface .......................................................................................... 8
Writing Your First Plug-In ...................................................................11
Writing the Plug-in ............................................................................................... 11
Creating the Plugin, Module and Process with Visual Studio ...................... 11
Inspecting the Files ...................................................................................... 15
Writing the Algorithm Code ........................................................................ 16
Running the Plug-in .............................................................................................. 18
Using the Online Help........................................................................................... 20
Opening the Online Help ............................................................................. 20
Using IntelliSense......................................................................................... 20
Accessing Class Definitions .......................................................................... 21
Understanding the Petrel Data Domain...............................................22
Exposing Petrel’s Data Model .............................................................................. 22
Entities and Properties ................................................................................ 22
User View of the Petrel Data Model ............................................................ 22
Data Access .......................................................................................................... 27
Common Exposed Data Types ..................................................................... 27
Read Access .......................................................................................................... 28
Browsing Collections.................................................................................... 28
Seismic Data................................................................................................. 28
Well and Geology......................................................................................... 29
Pillar Grid Model .......................................................................................... 30
Simulation and Data Analysis ...................................................................... 31
Updating Data ...................................................................................................... 31
Using Transactions ....................................................................................... 31
Modifying Domain Objects .......................................................................... 32
Accessing Domain Object Relationships ...................................................... 32
Domain Object Creation ....................................................................................... 33
Creating New Instances ............................................................................... 33
Creating New Collections............................................................................. 34
Welcome to Ocean for Petrel
Ocean Architecture
The Ocean architecture consists of three levels: the Core, the Services, and the product family.
For model-centric applications, the product family is Petrel. Ocean modules are managed by the
Core layer. They interact with all levels of the framework, as shown in Figure 1:
Application Module
Deployed as plug-in or extension module
Schlumberger or 3rd party
Product Family
Ocean Services
Ocean Core
The Ocean Core plays the role of the basic infrastructure. It manages Ocean modules and
registers services, both the services pre-loaded by the product family as well as services that are
added dynamically via the application programming interface (API). The Ocean Core manages
the data sources provided by the product family or any external data source that could be
defined by any module. It also performs event management and basic message logging.
The Ocean Services are a set of application independent utilities. They are modules that benefit
from being standardized across product families. An example is the Coordinate Service – a utility
for converting between projection and geodetic coordinate systems. The Ocean Services layer
only depends on the Ocean Core or on other Ocean Services.
Welcome to Ocean for Petrel
The product family is the host for Ocean applications and is the environment in which the Ocean
module needs to run. The product family provides:
the domain objects and their data source
the graphical environment in which the applications will display their data
a common look and feel for all application user interface components
Application modules connect to all software layers as well as to the .NET framework. Application
modules can register their own services with the Ocean Core and benefit from services
registered by other modules. All applications built on the Ocean framework are designed in a
similar fashion, but they rely on a product family to build and run.
Windows:
o Adding custom windows
Renderers:
o Adding renderers for domain objects (native and custom) in different windows
Interactions:
o Adding custom window modes to define interactions in different windows
o Object picking in different windows for its manipulation
Menus and toolbars:
o Adding new menus to Petrel window or extending Petrel menus
o Adding new toolbars with custom tools
o Extending Petrel toolbars with custom tools
Petrel project explorer:
o Adding custom objects in Petrel tree in a particular hierarchy
o Adding processes and workflows in the Petrel process diagram and workflow
editor
This is not an exhaustive list.
The Ocean module has a defined lifecycle with certain requirements and restrictions that allow
the clean integration into the product family. Its lifecycle phases serve to license the module,
initialize and integrate it into the product family, add presentation interfaces, and remove all
these when the module is unloaded. The appearance and interaction is seamless and allows the
product family to treat the module as native code.
An Ocean module uses the functionalities provided by the product family, the Ocean Services,
the Ocean Core, and also the .NET architecture. It may also use third party application
assemblies and other modules.
Ocean for Petrel modules are built with Visual Studio 2011 or Visual Studio 2012 for .NET, with
the help of the Ocean for Petrel wizard. The wizard takes care of the interaction with the Core as
well as some low-level access to functionality provided by the Petrel product family.
Plugin class
An Ocean plugin derives from the abstract Plugin class, defined in the [Link]
namespace. During Petrel startup, the Ocean Core will load plug-ins and their contained modules
as defined in the [Link] file. The Plugin class contains information about the
plug-in and its identity. The following is an example module:
using [Link];
using [Link];
public class MyPlugin : Plugin
{ ...
public override string Name { get { return "Plugin Demo"; } }
public override PluginIdentifier PluginId
{ get { return new PluginIdentifier("PluginDemo", new Version("[Link]")); } }
public override IEnumerable<ModuleReference> Modules
{
get { yield return new ModuleReference(typeof(DemoModule));
yield return new ModuleReference(typeof(DemoModule2)); }
}
public override IEnumerable<PluginIdentifier> Dependencies
{ get { return new List<PluginIdentifier>(); } }
public override string Description { get { return "Example plug-in"; } }
public override string AppVersion { get { return "2014.0"; } }
public override string Author { get { return "Joe Smith"; } }
public override string ImageResourceName
{ get { return "[Link]"; } } // used if Plugin is licensed
public override string DeploymentFolder
{ get { return "OceanTraining"; } }
}
IModule Interface
An Ocean module implements the IModule interface. IModule is defined in the [Link]
namespace.
The IModule interface defines five methods of the module lifecycle phases and inherits from
IDisposable. The phases and their methods are:
Welcome to Ocean for Petrel
WRITING YOUR
FIRST PLUG-IN
Ocean for Petrel allows application developers to extend the Petrel functionality with new
custom processes and workflows. This chapter describes the procedure of creating a simple
process.
Ocean Plugin
template
Ocean
Project
type
It is generally a good practice to use a descriptive plug-in name. Change the name of your plug-in
to “ListSeismicPlugin”. Change the “Author”, “Contact”, “Plugin URL”, and “Description” fields as
appropriate. Also, since we are adding a module to the plug-in turn on the “Create new module”
and the “Register existing modules” checkboxes (See Figure 5.). Click Next in the dialog.
Writing Your
First Plug-In
The wizard will create the name of the module from the namespace with “.Module” appended.
Review the content (see Figure 6) and click Next in the dialog.
It is generally a good practice to use the name “Module” for the application module. Change the
name of your module to “ListSeismicModule”. Create a workstep in your module by checking
the New Workstep box; give it the name “ListSeismicCubes”. Click the Next button. (See Figure
7.)
Workstep
For your workstep, enter a Short description of “My First Ocean Process” and a Long description
of “This process will print the names of all seismic cubes in the current project”. Ensure that
Generate custom UI is unchecked in order to use the default UI automatically generated by
Ocean. This workstep should have its own process wrapper; ensure that Generate process
wrapper is checked. Click the Next button. (See Figure 8.)
Writing Your
First Plug-In
Do not specify any workstep arguments; they are not needed. Click the Next button. (See
Figure 9.)
Review what the wizard will generate and click the Finish button. (See Figure 10.)
The Wizard configures the ListSeismic project to make debugging simple. The assembly is output
to the Petrel installation directory. The project command line property is set up to start Petrel.
So debugging is simply a matter of building and starting the debugger.
The Wizard writes the basic code needed for the ListSeismicCubes plug-in. You will need to add
code for your specialized algorithm in order to print the names of all Seismic Cubes in the
current project.
Writing Your
First Plug-In
Plugin
The Plugin class contains properties which provide identity to the plugin and is generated by the
Pl
wizard from the values you entered and the Ocean version. Thes include AppVersion, Author,
Contact, Dependencies, Description, ImageResourceName, PluginUri, Modules, Name,
PluginId, and Trust.
Module
The Module class implements the IModule interface. The new process is added to the Process
T T T T
First the new ListSeismicCubes workstep is created, and then it is added to the Workflow editor.
Finally, the process is created from the workstep using the WorkstepProcessWrapper T T
convenience class. The new process is added to the process diagram using the
[Link] API. Putting the pieces together, the Wizard generated the
T T
ListSeismicCubes
The ListSeismicCubes class is the workstep class that holds the processing algorithm. Previously,
T T
arguments. The wizard implements much of the class for you, including the argument creation
and copy methods. Arguments creation is very basic. Arguments copy can be done with the
DescribedArgumentsHelper static class.
T T
The Wizard also implements two interfaces, IAppearance (for its appearance in the Process
T
diagram) and IDescriptionSource (to display information in the Process UI). We do not need the
T T
setters for Text and Image properties, so you may delete them.
ListSeismicCubes also contains an Arguments class created by the Wizard, which in this case is
T T T T
It implemented the IExecutorSource interface and an instance of the Executor class. You will add
the custom algorithm code to the ExecuteSimple method, which will be called when the
workstep or process is executed.
public class ListSeismicCubes : Workstep<[Link]>,
IExecutorSource, IAppearance, IDescriptionSource
{
#region IExecutorSource Members and Executor class
Writing Your
First Plug-In
Code the ExecuteSimple method. The work for the process is completed as follows:
Read the current project using the [Link] API. Use the static class
SeismicRoot to find the root of all domain objects in the seismic domain. It exposes a property
SeismicProject, which provides navigation to all seismic collections and interpretation
collections in the project. Parse through all the seismic collections and print the names of all
seismic cubes within them using the InfoOutputWindow method of the PetrelLogger class. Build
a dynamic list of surveys (SeismicCollection) to avoid recursive calls while providing a breadth
traversal of the survey tree. The PetrelLogger static convenience class provides static methods
T T
information message that is intended for all end users to see, but without being highly
interruptive.
The following shows the complete Executor class:
using [Link];
public class Executor : [Link]
{
Arguments arguments;
Writing Your
First Plug-In
WorkflowRuntimeContext context;
public Executor ( Arguments arguments, WorkflowRuntimeContext context )
{
[Link] = arguments;
[Link] = context;
}
public override void ExecuteSimple( )
{
// Get current primary project
Project proj = [Link];
// Get the root of all domain objects in the seismic domain
SeismicRoot root = [Link](proj);
SeismicProject sProj = [Link];
finish building the solution and run Petrel with your plug-in.
Build your solution in Visual Studio. This will create the assembly for the plug-in. It will also
create a [Link] file and merge its contents into the [Link] file. The
[Link] file exists under your %AppData% directory for your account on your
PC. Typically this is C:\Users\<username>\AppData\Roaming\Schlumberger\Petrel\2014\. This
file is used when Petrel is started to define the plug-ins, and their associated modules, which will
be loaded by the Plugin Manager.
Start Petrel.
In Petrel, open the demo project deployed with the Ocean SDK. Then go to the Process diagram
window and find ListSeismicCubes (12).
Writing Your
First Plug-In
Double click ListSeismicCubes to start the process and display the ListSeismicCubes dialog.
The short and long descriptions are shown in the top section of the dialog. There are no
arguments for the process, so the lower section is empty, as shown in the following figure.
Click Apply to run the process. The ListSeismicCubes process will show the seismic cubes in the
Petrel message log (Figure 14).
Exit Petrel.
You have now written, built, and run your first Ocean plug-in. You can find further details about
the Ocean Wizard and the functionality it offers in the Appendix of this document.
Hit F1 on a class, interface, property, method or other part of the Ocean API while you are in the
Visual Studio editor window to bring up the corresponding help in a browser window, like you
can for Microsoft APIs.
You can open the [Link] file directly from the Documentation folder of the Ocean SDK
installation directory or from the Ocean Start Page in Visual Studio.
Using IntelliSense
In Visual Studio, the Ocean library references (files with “.dll” extensions) allow the environment
to select class members and methods from a list that is dynamically generated from the types of
the variables in the code. This feature helps you select the correct class syntax without having to
explicitly search for information in the Ocean help.
Writing Your
First Plug-In
Select Go To Definition. The following editor opens in your Visual Studio environment.
Understanding the Petrel Data Domain
Templates
Each property object in Ocean has a template associated with it so that the application working
with it has a way to determine how to display the property values. The template defines the
units, scale, and color table used by the object. The templates are found in the
[Link].
Processes
All the trees are accessible via the API. Data is organized in pseudo-folders, seen in the API as
object collections. Each view is described in the following sections.
Input Data
The Input Data function gathers all data that is needed to build a static model. This includes all
data acquired and processed (well logs, geological markers, seismic data sets, seismic attributes)
and all data that is interpreted from the field measurements (petrophysical properties, seismic
time interpretations, velocity functions).
Most domain objects visible in the Input data tree are accessible in Ocean from the following
specialized collections:
BoreholeCollection – This collection class contains boreholes, logs, and completions, as well as
nested BoreholeCollections. See the Well data model for details.
MarkerCollection – This is the geology data model. These collections contain markers, horizons,
zones, and fluid contacts.
SeismicCollection – This collection is for 3D and 2D seismic collections.
InterpretationCollection – This collection is for all seismic interpretation.
Collection – Other folders are accessible as generic collections. From these collections, the API
can access point sets, polyline sets, and surfaces.
Understanding the Petrel Data Domain
Models
The Models data tree includes all elements of the pillar grid static model and the property
objects that represent property distributions throughout the pillar grid cell array.
Domain objects visible in the Models data tree are accessible from the following collections:
ModelCollection. This top level container in the Models tree enumerates all the Models (pillar
grids) in the tree. Model collections are not nested.
[Link]. Specific to each model, the collection lists all property and fault
property instances in that model.
[Link]. This collection lists all fault properties, per fault, in a pillar grid model.
Understanding the Petrel Data Domain
Results
Results are simulation results imported back in Petrel to compare the static models with their
possible evolution through time. They are available as CaseResults from the simulation Case.
You can then get all SummaryTimeSeries and GridPropertyTimeSeries or the ones
corresponding to a given SummaryResult or GridResult.
Cases
The Cases tree exposes simulation cases based on different hypotheses but also represents
various interpretation versions driving static model property variations. You can access Case,
AnalysisCase, and CalculationCase instances from SimulationRoot. There is currently no
hierarchy in the Ocean API.
Understanding the Petrel Data Domain
Templates
The Templates tree exposes templates that are used by the Petrel user to define the data type
for the domain objects in the project. The templates are not domain specific. This means that
the Porosity template may be used to represent data for a Porosity well log as well as a Porosity
property of a pillar grid.
Processes
The Processes tree exposes the Petrel processes used by the Petrel user to perform various
actions on data. The processes are interactive in nature in that activating one causes the process
toolbar on the right side of the Petrel UI to update to indicate the tools that are available to the
process.
Understanding the Petrel Data Domain
Data Access
The Ocean for Petrel API offers the following data access types:
Read: The API reads existing data, browsing through data folders, enumerating collection
contents and following the parent-child relationships.
Update: The API updates existing objects, modifying entity characteristics (such as its geometry)
and modifying property values (like correcting log values in chosen points).
Create: The API creates new instances of Petrel object classes, augmenting the project with new
data the same way Petrel applications do.
Delete: The API deletes objects that are no longer needed in the project.
Seismic
Well
Geology
Ocean classes for well marker data, sometimes referred to as well tops, are found in namespace
[Link].
You can create stratigraphy columns across a number of wells. Fault and interface-type surfaces
are just named references.
Shapes
Ocean classes for objects defining various shapes are found in the namespace
[Link].
You can add properties to point sets, surfaces, and polyline sets. Surfaces can be irregular or
gridded (regular height field), though only regular height field surfaces can be created. Both can
be assigned property values.
Understanding the Petrel Data Domain
Pillar Grid
Ocean classes for pillar grids and their related objects are found in the namespace
[Link].
Pillar grid property retains some knowledge of statistical treatment completed at creation time,
including which cells have been upscaled as well as statistical distributions of facies values.
Simulation
Ocean classes for simulation cases and simulation results are found in namespace
[Link].
A simulation case has a number of case runs, each providing time series (results vs time) data for
combinations of result categories (fields, wells) and result properties (oil production, water flow
rate, etc.).
Streamlines can be added to various stream line sets in a simulation case. Property values can
also be read and appended and new property types added.
Read Access
Browsing Collections
There is no query service implemented on the Petrel Project as it is not implemented in a
relational database. Instead, data browsing is done by following the non-taxonomic hierarchy. At
the top level of each domain is a root object which gives you access to all of the data in that
domain. It is possible to browse through the whole data domain of a project by starting from the
different root objects.
Root objects offer access to collections, which may be nested. From each collection, the API can
access the entities and the properties that are relevant to that collection type.
Seismic Data
Seismic data is rooted in the project’s SeismicProject instance (which is a singleton) once it has
been created. It is accessed, if it exists, from the SeismicRoot of the project. It only exists if
seismic data are included in the project.
Below the SeismicProject are two separate hierarchies in the Seismic domain, one for seismic
Understanding the Petrel Data Domain
data with nested SeismicCollection objects, the other for interpretation picks with a nested
hierarchy of InterpretationCollection instances.
Project proj = [Link];
SeismicRoot sr = [Link](proj);
SeismicProject sp = [Link]();
// navigate the Seismic data hierarchy
foreach (SeismicCollection scol in [Link])
{ ... }
// navigate the Seismic interpretation hierarchy
foreach(InterpretationCollection icol in [Link])
{ ... }
Once the WellRoot instance is retrieved by the system, it gives access to borehole and marker
Understanding the Petrel Data Domain
collections.
public sealed class WellRoot : ...
{ ...
public BoreholeCollection BoreholeCollection { get; }
public int WellLogVersionCount { get; }
public IEnumerable<PropertyVersion> WellLogVersions { get; }
public int MarkerCollectionCount { get; }
public IEnumerable<MarkerCollection> MarkerCollections { get; }
}
Boreholes are in nested collections, rooted at the top level collection retrieved from WellRoot.
Marker collections are not nested. Lists of collections, each corresponding to a different
stratigraphic classification, are at the top level.
Pillar grids are in a hierarchy that contains the property hierarchies. Hierarchy retrieval starts
from the PillarGridRoot object.
PillarGridRoot grid = [Link](proj);
IEnumerable<ModelCollection> mcolls;
mcolls = [Link](proj);
foreach (ModelCollection mcol in mcolls)
{
foreach (Grid g in [Link](mcol)
{ ... }
}
Each Grid object interfaces a full static model with intersecting horizons and pillar-based faults.
Grid g = ...
foreach (Fault f in [Link])
{ ... }
foreach (Horizon hor in [Link])
{ ... }
The model is populated by property values that are accessed in a nested hierarchy of
PropertyCollection folders.
Grid g = ...
PropertyCollection pcol = [Link];
foreach (Property prop in [Link])
{
Understanding the Petrel Data Domain
Simulation cases, result properties, and result hierarchies belong to separate hierarchies. The
time series are defined by combinations of these.
Simulation case runs are retrieved from SimulationRoot. The simulation case gives access to
simulation results and streamlines. For time series, the result property and category must be
supplied by the application.
SimulationRoot root = ...
foreach (Case case in [Link])
{
StreamlineSet sls = [Link];
if (sls != [Link])
foreach (StreamlineSubset sub in [Link])
foreach (Streamline sl in [Link])
{ ... }
}
Updating Data
Your application can update data by modifying the object that is seen through the API. Updating
an entity or a property object alters the project. After updating the project, you must decide
whether to save the project changes or not. From the API standpoint, however, the project has
been modified as soon as an object has been edited.
You must make any such updates inside a transaction and any modified object must be locked
beforehand inside that transaction.
Using Transactions
A transaction represents a group of edits made to data (domain objects). Transactions are
required for operations on native Petrel domain objects that will change the data: create,
Understanding the Petrel Data Domain
The array of log values, Samples, is read-write but SampleCount is read-only (dynamically
evaluated from the array size).
Most objects accessible via the API can be instantiated. However, the API never allows class
instantiation in the classical manner. API classes are sealed, and some objects are even exposed
simply as interfaces. To create a new class instance, the API has specialized Create methods.
Using Transactions
The plug-in code must create domain objects inside transactions, just like object updates.
However, an object creation modifies its parent entity (in the non-taxonomic hierarchy) or the
collection of similar entities that will harbor it. That parent or collection has to be locked in the
transaction.
You can modify the newly created object until the transaction commits. It is locked by default,
only its parent had to be locked explicitly in the transaction.
The Create method is always located in the class of the containing object. Borehole contains
WellLog collections where the Create method for logs can be found.
using (ITransaction t = [Link]())
{
Template template = ...
WellRoot wr = [Link]([Link]);
LogVersionCollection rootLVCol = [Link];
[Link](rootLVCol);
WellLogVersion version = [Link](“Gamma”, template);
Borehole bh = ...
[Link](bh);
Understanding the Petrel Data Domain
WellLog wl = [Link](version);
...
}
For top-level objects (like collections) the Create methods are in static classes. For example, the
top level collection for Seismic data is created in the SeismicProject instance.
There are few collections that can appear at the top level of Petrel data trees. Nested collections
are rooted under a top level collection that is only created once. Un-nested collections that can
be added at the root of Input or Models data trees include the following:
MarkerCollection
ModelCollection
Collection
These collections are created directly from the Petrel primary Project or the WellRoot object.
ITransaction t = ...
Project proj = [Link];
WellRoot root = [Link](proj);
[Link](proj);
[Link]("New Pillar Model");
[Link](root);
[Link]("New Stratigraphic Model");
[Link]();
[Link]();
Nested Collections
Collections that are always grouped under a root collection are created using a specific
container, WellRoot for boreholes and SeismicProject for seismic data and interpretation. These
are used for the following nested collections:
SeismicCollection
InterpretationCollection
Understanding the Petrel Data Domain
BoreholeCollection
There is no specific object at the root of all borehole collections, instead there is a generic
BoreholeCollection called “Wells” that you can only create once.
ITransaction t = ...
Project proj = [Link];
SeismicRoot root = [Link](proj);
SeismicProject sproj = [Link];
WellRoot wroot = [Link](proj);
[Link](sproj);
string colName = "New Collection";
SeismicCollection scol = [Link](colName);
String iName = “New Interpretation”);
InterpretationCollection icol;
icol = [Link](iName);
...
[Link](wroot);
BoreholeCollection bcol = wroot. GetOrCreateBoreholeCollection();
...
You can also create collections that are placed under an object container, for example, under the
PillarGrid.
ITransaction t = ...
Grid g = ...
[Link](g);
PropertyCollection root = [Link];
String colName = “New Properties”;
PropertyCollection sub = [Link](colName);
...
Deleting Objects
Deletion of an existing instance is done by calling the Delete method on the object itself.
Deletion is always done inside a transaction and the object to be deleted must be locked first.
Retrieving Models
To retrieve the latest model:
Grid latest = [Link];
DateTime last = new DateTime(1980, 1, 1);
PillarGridRoot proot = [Link](proj);
Understanding the Petrel Data Domain
Filling Values
To fill values:
IPillarGridIntersectionService ipgs;
ipgs = [Link]<IPillarGridIntersectionService>();
Creating UI Tools
A tool is an item that appears on menus and toolbars. When a tool appears on a menu as a
menu item, it is drawn as a list entry with text as well as an optional image as shown in the
following example.
tool in toolbar
Ocean provides a set of convenience classes that extend the PetrelTool class to create tools such
Extending the Petrel UI
as a menu item.
public class PetrelMenuItem : PetrelTool, ...
{ ...
public PetrelMenuItem( string txt );
public PetrelMenuItem( string txt, Bitmap image );
}
You can also optionally provide an image and an event handler for a menu click.
Text
UI Location
To specify the UI location of the new menu item, you need to specify the menu to which it will
be added. In this case, the location is an existing Petrel menu as shown below.
The Ocean WellKnownMenus static convenience class has a public static PetrelMenuItem field
for each existing Petrel menu.
public static class WellKnownMenus
{
public static PetrelMenuItem File { get; }
public static PetrelMenuItem Edit { get; }
public static PetrelMenuItem View { get; }
public static PetrelMenuItem Insert { get; }
public static PetrelMenuItem Project { get; }
public static PetrelMenuItem Tools { get; }
public static PetrelMenuItem Window { get; }
public static PetrelMenuItem Help { get; }
}
This new menu item should be placed in the Tools menu, so you should specify the Tools field.
Extending the Petrel UI
Image
You also have the option to set the image for the menu item. You can use an image from Petrel
that is available from the static class PetrelImages, or you can provide your own.
[Link] = PetrelImages.Seismic3D;
Finally you need to specify what is going to happen when the menu item is clicked. For this
example, the menu item will run the same algorithm that you wrote for your workstep.
To specify the action, add a click handler to the menu item instance:
[Link] += myListSeismicToolClick;
You will add the new tool to the UI after the tool is created:
[Link](myListSeismic);
Extending the Petrel UI
Now, after you rebuild your module and run Petrel, you will see a new menu item called “List
Seismic Cubes” in the Petrel Tools menu:
Figure 12: New “List Seismic Cubes” Menu Item in Petrel Tools Menu
Extending the Data Domain
public float X
{
get { return m_x; }
set { m_x = value; }
}
public float Y
{
get { return m_y; }
set { m_y = value; }
}
public float Z
{
get { return m_z; }
set { m_z = value; }
}
{
get { return m_radius; }
set { m_radius = value; }
}
}
This basic object is a valid custom domain object that can participate in Petrel behavior. It can be
added to the Petrel Input and Model trees.
Use the [Link] property to add to the Input tree, and the [Link]
property to add to the Models tree. You must use a transaction when adding the children. The
transaction is created by the DataManager class. Lock the object that is going to have new
children, then commit the transaction to complete the operation.
using (ITransaction txn = [Link]())
{
Project proj = [Link];
[Link](proj);
[Link](new XYZObj( ));
[Link](new XYZObj( ));
[Link]();
}
This example adds a XYZObj custom domain object to a Borehole, a native Petrel domain object.
Begin with a Borehole object. Lock the Borehole since you are going to change its children. Add
a new XYZObj using IExtensions. Putting it all together, you have the following:
[Link] bore = ...;
using (ITransaction txn = [Link]())
{
[Link](bore);
[Link](new XYZObj());
[Link]();
Extending the Data Domain
Add the new context menu item in the module’s IntegratePresentation method. Create a
Borehole context menu item. Add it to the Petrel UI using the [Link] service.
SimpleContextMenuHandler<Borehole> cItem =
new SimpleContextMenuHandler<Borehole>(“Insert XYZ object”,
[Link], false, AddXYZClick );
[Link]( cItem );
Provide an event handler to respond to the click of the context menu item. The AddXYZClick
event handler will add the XYZObj object to the Borehole from the context menu.
public void AddXYZClick( object sender, ContextMenuClickedEventArgs<Borehole> e )
{
Borehole bore = [Link] as Borehole;
using (ITransaction txn = [Link]())
{
[Link](bore);
[Link](new XYZObj());
[Link]();
}
Extending the Data Domain
The new “Insert XYZ object” context menu item is added to the bottom of the Borehole context
menu as shown in the following figure.
You can control an object’s appearance in the Petrel trees by implementing the
[Link] and [Link] interfaces
and providing implementations of the abstract NameInfo and ImageInfo classes.
INameInfoSource and IImageInfoSource allow the custom domain object to provide a text string
and a bitmap to be displayed in the user interface. Implementing INameInfoSource and
IImageInfoSource for the XYZObj object is as follows:
using [Link];
public class XYZObj : INameInfoSource, IImageInfoSource
{ ...
private Bitmap myRedCircle = [Link];
private NameInfo nameInfo;
public NameInfo NameInfo
{
get
{
if (nameInfo == null) nameInfo = new DefaultNameInfo("XYZ Object",
"XYZ Object", "[Link]");
return nameInfo;
}
}
private DefaultImageInfo m_imgInfo;
public ImageInfo ImageInfo
{
get
{
if (m_imgInfo == null) m_imgInfo = new DefaultImageInfo(redCircle);
return m_imgInfo;
}
}
}
Extending the Data Domain
3D Window Display
You must perform the following steps to render a custom object in the 3D or 2D window.
Implement a renderer for the 3D window for the object type.
Add the renderer service to Ocean.
Implement the IWindow3DRenderer interface to provide a renderer for the 3D window for
displaying your object. Create a class to implement IWindow3DRenderer and implement the
following IWindow3DRenderer methods. CanCreate determines if the domain object can be
rendered in the window. It can use properties of the object or the context to decide. Create is
called the first time an OpenInventor scenegraph is needed to display an object. It creates the
OpenInventor node structure. The position of the XYZObj object is translated into the window
coordinates. A sphere is defined to represent it, and is added to the node hierarchy. The Update
method is called when the scenegraph may be stale. (Refer to OpenInventor documentation for
details.) Dispose should clean up any resources associated with the scenegraph and the node
you are sent.
The complete OpenInventor factory class for rendering the XYZObj object is shown in the
following example:
using [Link];
using [Link];
using [Link];
[Link] = vec3;
[Link](trans);
// create a sphere
mySphere = new SoSphere();
[Link] = [Link];
[Link](mySphere);
return root;
}
Add the OpenInventor factory as a service in the module’s Initialize method to display the
XYZObj object.
public void Initialize ( )
{
Type objType = typeof( XYZObj );
Type factoryType = typeof(IWindow3DRenderer);
XYZObjOivFactory factory = new MyXYZ3DRenderer( );
[Link]( objType, factoryType, factory);
}
When a 3D window is active, the XYZObject object will have a checkbox next to it indicating that
it may be displayed.
When the end user clicks the checkbox the object will be displayed.
{
XYZObj xyz = (XYZObj)o;
double x = xyz.X;
double y = xyz.Y;
double size = [Link];
Point2 begin = new Point2( x - size, y - size );
Point2 end = new Point2( x + size, y + size );
Register the drawing service with Ocean in the module’s Initialize method.
Type xyzType = typeof(XYZObj);
Type factoryType = typeof(IMapRenderer);
XYZObjMapDisplay mapFactory = new XYZObjMapDisplay();
When the end user checks the checkbox, the XYZObject is rendered in the Map window.
Have the XYZObj class implement IIdentifiable. You will use the structured data source to
generate the Droid and add a custom object instance to the data source. Make the following
additions to your XYZObj class.
public class XYZObj : ..., IIdentifiable
{ ...
Droid m_droid;
StructuredArchiveDataSource m_dataSource;
// add Constructor
public XYZObj()
{
IDataSourceManager mgr = [Link];
this.m_dataSource = [Link](mgr);
this.m_droid = [Link]();
[Link](m_droid, this);
// set initial values:
m_x = 100.0f; m_y = 0.0f; m_z = 0.0f; m_radius = 100.0f;
}
public void Droid Droid
{
get { return m_droid; }
}
}
You must also tag your class and any members you want to serialize into the structured archive
Extending the Data Domain
You must register your data source factory with the system in your [Link] using
the [Link] method:
public class Module : IModule, ...
{ ...
public void Integrate()
{ ...
[Link](new XYZObjDataSourceFactory);
}
}
Next you will create your object and add it to the tree, providing the data source instance in the
object’s constructor. You will retrieve your data source factory from the Get method you added
to it above.
public void CreateXYZObj()
{
// create XyzObj instance and provide data source
XyzObj xyz = new XyzObj();
Project project = [Link];
using (ITransaction t = [Link]())
{
[Link](project);
// Add XyzObj to project extensions.
[Link](xyz);
[Link]();
}
}
When you save the project, the XYZObject is saved with it. Reopening the project will load this
data back into Petrel.