Engineer´s guide to blowout simulations via Oliasoft API

Engineer´s (beginners) guide to blowout simulations via Oliasoft API

In this article, we will look at how we can setup communication with Oliasoft API to perform a full Blowout simulation and retrieve a result from the simulation. The following article is a non-technical article in the sense that it is made by a drilling engineer, so professional developers will solve this differently. Regardless, the article will show a step-by-step guide, with references to additional resources that you can use if you want to have a go at it.

Final JSfiddle link here

 

Setting up an environment

In order to write code we normally need to setup a coding environment. I don´t want to do that though, so we will use the following resources instead:

  1. A valid Oliasoft account. You will need a valid username and password to connect to the API. If you don´t have one, sign up for an Oliasoft Trial here.
  2. https://jsfiddle.net - A sandbox environment already setup to perform coding. It can be a little cramped for larger projects, but we will make sure we keep our code nice and compact.
  3. https://www.oliasoft.com/developers - This is the location of Oliasoft´s API documentation. we need to look at this to connect to the API´s properly
  4. http://myjson.com - This is simple storage container where we can put some json files, so we don´t have to clutter our code with large objects

That is about it.

Let´t get started with jsfiddle.

In order to make things look nice and shiny, we have to do some minor setups to it.

Head over to https://jsfiddle.net and start a new fiddle. You will see something like this:

JSfiddle setup

There are 5 areas to know:

  1. The metadata section. Also, this is where we can link to external resources we might need. We dont want to do that though, we will import what we need directly in the other sections.
  2. HTML section - This is where we can write HTML, to actually show something on our canvas
  3. Javascript section - This is where our code that communicates with Oliasoft API will go
  4. CSS section - This section just lets our project know how to apply styles. In general, this will make our canvas nice and shiny.
  5. Our canvas. This is our to populate as we want. We will keep this nice and tidy, but we may want to ask for some inputs or display some results here.

Whenever we change code in any of the sections, we can push the "RUN" button at the top left corner to run our code.

Importing style-sheet

Ok, to make sure we import our CSS (our styling) correctly, lets just make a simple button. Paste the following into the HTML area:

<button type="button" class="btn btn-primary">This is my button</button>

 

Click RUN and we will get something that looks like this in our canvas area:

HTML button

We now have a "no styled" HTML button. We want to make it look nicer. There are many styles  to choose from, but in this article we will use a framework called "Bootstrap". It is just one of many simple styling frameworks that makes things easy for us. Lets paste the following into the CSS section:

@import url('https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css');

This essentially imports a full styling-set for a bunch of components into our projects. If we push "RUN", we will see that our button has changed.

Styled HTML button

This is a confirmation that we have imported our styling sheet correctly. Congratulations! Delete the HTML and lets move on.

Setting up variables for Oliasoft API

In order to communicate with Oliasoft´s API for blowout simulations, we can setup some variables to make this easy for us. We will have to setup 2 things:

  1. URL´s to/from Oliasoft API
  2. JSON object (what data we should send to it)

Lets begin with the URL´s. If we head over to https://www.oliasoft.com/developers we can go and have a look at the blowout API.

Oliasoft API documentation page

Click on "Blowout Documentation". Now you will see a lot of documentation for how to use this API. We will dig into the details later, but for now we only need the URL´s listed on the front page".

This will give us the following 3 URL´s:

  1. https://blowout.oliasoft.com/BlowOutSimulationAPI/api/BlowOut
    (to paste the payload. This will also return an ID number for the simulation)
  2. https://blowout.oliasoft.com/BlowOutSimulationAPI/api/Status/(your ID number)
    This will return the status of the simulation
  3. https://blowout.oliasoft.com/BlowOutSimulationAPI/api/BlowOut/(your ID number)
    This will return the final results

Great. Now that we have those URL´s, lets set up the variables in the javascript section. The following code will do:

let startURL = "https://blowout.oliasoft.com/BlowOutSimulationAPI/api/BlowOut";
let statusURL = "https://blowout.oliasoft.com/BlowOutSimulationAPI/api/Status/";
let resultURL = "https://blowout.oliasoft.com/BlowOutSimulationAPI/api/BlowOut/";

To make this specific example work on jsfiddle, we need to add another URL. There is an IT-technical reason for this, but for now, just add the following line.

let cors = "https://cors-anywhere.herokuapp.com/";

Next up we need some data to send. For now, we will just declare the variable but at the same time we can prepare the data that will eventually go into it. Let´s use the example provided by Oliasoft. Click the "Example" in the Blowout documentation and copy the full JSON object. We COULD paste this whole thing into our jsfiddle project, but to keep this tidy, lets instead head over to myjson.com and paste it there. When you save it, it will return a URL for you with that data. My URL became the following: https://api.myjson.com/bins/12e960

This is the data, or "payload" that we will use for the simulation. Awesome! Lets remember that URL, we will need it soon.

 

Setting up our canvas to display results

Now, lets add some elements to our canvas so that we can see what is going on. We will need 3 components:

  1. A button to start a simulation
  2. An indicator to show us the status of the simulation
  3. A result area, perhaps a chart showing some information.

Lets start setting these up. Add the following HTML:

<center>

<button id="startButton" type="button" class="btn btn-primary">Start a blowout simulation</button>

<div id="spinner" class="spinner-border spinner-border-sm" role="status"></div>
  
  <p id="spinnerText"></p>
  
  <p id="statusText"></p>

  <p id="results"></p>
  
  </center>

Also, add the following CSS:

#spinner, #spinnerText, #statusText {
  display: none;
}

So what have we done here. We have a button, allowing us to start the simulation. We have a spinner and text to let us know the status while the simulation in ongoing, and an area to display the results. We don´t want these to show before we have anything to show however, so the CSS just temporarily hide those components until we get started. We will change them with javascript soon.

 

Setting up javascript functions

Next up, we need to make the button actually do something when it is pressed. It should start a blowout simulation, so we must make a function to do just that. Additionally we will add the following routine:

  1. Send payload to Oliasoft API
  2. Listen at status and display the updated status continuously.
  3. When simulation is done, display some results. We can start off with a simple number.

So first things first.

Lets set up the functions.

var startButton = document.getElementById("startButton");

startButton.onclick = () => {

//We can do something here

}

const sendPayloadToOliasoftAPI = () => {

//We can do something here

}

 const fetchStatus = (id) =>{

//We can do something here

}

 const displayStatus = (message) => {

//We can do something here

}

const retrieveResults = (id) => {

//We can do something here

}

Let´s see what is going on here.

  1. We have declared another variable "startButton" and loaded it through "document.getElementByID"
  2. We have declared functions for "sendPayloadToOliasoftAPI" (our dataset that we want to calculate on), "fetchStatus" (get the updated status from the calculation),  "displayStatus" (will display the current status), and finally "retrieveResults" (which will get results and display a value).

We need to fill all these functions with instructions to achieve this.

 

 

 

In all functions calling the API, we will use the fetch() function.

Lets start with sendPayloadToOliasoftAPI().

 const sendPayloadToOliasoftAPI = () => {
 
fetch(cors+startURL, {

    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(simulationPayLoad)

}) 

.then(response => response.text())
.then(contents => { 
simresponse = contents;
let sim = JSON.parse(simresponse);
fetchStatus(sim.Id);
})
.catch(() => console.log("Can’t access " + startURL + " response. Blocked by browser?"))

 }

Lets see whats going on.

  1. We "fetch" the URL cors+startURL using the POST method, which means, that we need a body (the data that we will be sending). Instead of sending the full dataset inside this body, we send the variable that we created earlier (simulationPayLoad).
  2. When the response comes from the Oliasoft API, it will give us a simulation ID. Then we call the next function with that id as an argument "fetchStatus(sim.id)".

Great. Then we can head over to fetchStatus and populate that function.

 

Lets do something like the following:

 const fetchStatus = (id) =>{
 
fetch(cors+statusURL+id, {

    method: 'GET',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },

})
.then(response => response.text())
.then(contents => { 
document.getElementById("startButton").disabled = true;
let isSimulationFinished = JSON.parse(contents);
    if(isSimulationFinished.Status == "Finished") {
    retrieveResults(id);
    } else {
    displayStatus(isSimulationFinished);
    fetchStatus(id);
    
    }
 })
 }

This is whats happening here:

  1. We use the same fetch method as before, but we are using the GET method now. In order to let Oliasoft API know what we want to get, we need to add the simulation id at the end of our URL (as described in Oliasoft API documentation).
  2. Then, the API will return the status of the calculation.
  3. We add an if sentence, and say that IF the calculation is finished, then move on to the function "retrieveResults". If it is not finished, then run the "displayResults" function and then run our "fetchStatus" function one more time. This way, this function will loop until the status responds with a "finished" call.
  4. Also, I have added a simple expression to disabled our button while the simulation is actually running to avoid someone triggering multiple simulations with the same data.

Ok. Lets look at the next function "displayResults" which is a very simple one.

 const displayStatus = (message) => {
 
document.getElementById("spinnerText").innerHTML = message.Status;
document.getElementById("statusText").innerHTML = message.StatusText;
 
 }

This function takes in a "message", and then give our HTML elements a piece of the information each. Our "spinnerText" element is given the Status, and our "statusText" element is given the more descriptive status text.

Thats it.

Almost there.

Now we only have one last function to populate. This is our retrieveResults function. As seen, this function will be called when the API returns a status = "Finished". It means that it has some results that we can access.

This is very similar to the other functions, just a new URL. Lets have a look at it.

const retrieveResults = (id) => {
  
 fetch(cors+resultURL+id, {

    method: 'GET',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },

}) 

.then(response => response.text())
.then(contents => { 
let contentsJson = JSON.parse(contents);

document.getElementById("spinnerText").innerHTML = "Total weighted oil rate is "+Math.round(contentsJson.MeanOil.ProbabilisticTotalRate*10)/10+" m3 oil per day";

document.getElementById("startButton").disabled = false;
document.getElementById("spinner").style.visibility = "hidden";
document.getElementById("statusText").style.visibility = "hidden";

   
})
.catch(() => console.log("Can’t access " + startURL + " response. Blocked by browser?"))

  
  }

Again, we are using fetch with the GET method, using the simulation id.

We put all contents in the response into the variable called contentsJSON. We then display a result, the "MeanOil.ProbabilisticTotalRate" , and then we wrap that in an understandable text. Next up, we just hide the status text elements and make our button active again.

 

Congratulations. You have just completed a full blowout simulation, using numerous servers to calculate the results, and made a round trip by displaying the results.

We chose to display one number here, but the response from the server contains a LOT of information that you can choose to display in numerous ways. We will look at how we can display more results, charts and options in a later post.

The following list describes some of the results that you can choose to display here.

 

VariableSub-variablesComments
ProjectData- Company
- Field
- Location
- Well
- Platform
- Responsible
- Date
- Comments
This entry contains various project information given as input of the simulation
MeanOil- ProbabilisticTotalRate
- TopsideStringRate
- TopsideAnnulusRate
- TopsideOpenHoleRate
- SubseaStringRate
- SubseaAnnulusRate
- SubseaOpenHoleRate
- ProbabilisticTotalVolume
- TopsideStringVolume
- TopsideAnnulusVolume
- TopsideOpenHoleVolume
- SubseaStringVolume
- SubseaAnnulusVolume
- SubseaOpenHoleVolume
- Duration
This entry contains the main aggregated result-data, with final weighted rates for various scenarios.

The example in this post used the entry called "MainOil.ProbabilisticTotalRate"
MeanGasSame as aboveSame as above, for gas
MinimumOilSame as above
MinimumGasSame as above
MaximumOilSame as above
MaximumGasSame as above
TenPercentOilSame as above
TenPercentGasSame as above
FiftyPercentOilSame as above
FiftyPercentGasSame as above
NintyPercentOilSame as above
NintyPercentGasSame as above
DurationPlotDataMainX
MainY
CumulativeDistributionFunctionX
CumulativeDistributionFunctionY
MinimumX
Percentage10X
Percentage50X
Percentage90X
MaximumX
MeanX
StandardDeviationLeftX
StandardDeviationRightX
StandardDeviation
LineY
PhaseType
ExitPoint
FlowLocation
PenDepth
This entry contains main plot data (X and Y values) for a range of calculated ranges
RateVsTimePlotDataSame as "DurationPlotData" per time step. Typically 100 time steps per simulation.This entry contains the same as above, but for every single time step of the simulation. That means that you can plot f.ex "CumulativeDistributionFunctionX" for time step 0-99 and see how they develop.
VolumePlotDataSame as "DurationPlotData" per time step. Typically 100 time steps per simulation.
DetailsTopSideString- MD
- TVD
- Length
- Diameter
- Pressure
- Temperature
- Holdup
- FrictionFactor
- FrictionPressureLoss
- GravityPressureLoss
- SlipLiquidVelocity
- SlipGasVelocity
- SuperficialLiquidVelocity
- SuperficialGasVelocity
- TotalNoSlipVelocity
- OilDensity
- GasDensity
- MixDensity
- OilViscosity
- GasViscosity
- OilFormationVolumeFactor
- GasFormationVolumeFactor
- OilMassFlowRate
- GasMassFlowRate
- TotalMassFlowRate
- OilGasInterfacialTension
- DissolvedGOR
- BubblePointPressure
- NodeAngle
- FlowRegime
Contains detailed calculated results for many flow parameters for every depth point. Each depth point is typically 30m each.

Example, find flow temperature at depth 300mMD, use the following:

"DetailsTopSideString.10.Temperature
DetailsTopSideAnnulusSame as "DetailsTopSideString" per depth step
DetailsTopSideOpenHoleSame as "DetailsTopSideString" per depth step
DetailsSubSeaStringSame as "DetailsTopSideString" per depth step
DetailsSubSeaAnnulusSame as "DetailsTopSideString" per depth step
DetailsSubSeaOpenHoleSame as "DetailsTopSideString" per depth step
VLPResults- MeanVLPTopsideString
- MeanVLPTopsideAnnulus
- MeanVLPTopsideOpenHole
- MeanVLPSubseaString
- MeanVLPSubseaAnnulus
- MeanVLPSubseaOpenHole
- VLPTopSideString
- VLPTopSideAnnulus
- VLPTopSideOpenHole
- VLPSubSeaString
- VLPSubSeaAnnulus
- VLPSubSeaOpenHole
Plot data (X and Y values) for various VLP curves
IPRResults- MeanIPRTopsideString
- MeanIPRTopsideAnnulus
- MeanIPRTopsideOpenHole
- MeanIPRSubseaString
- MeanIPRSubseaAnnulus
- MeanIPRSubseaOpenHole
- IPRTopSideString
- IPRTopSideAnnulus
- IPRTopSideOpenHole
- IPRSubSeaString
- IPRSubSeaAnnulus
- IPRSubSeaOpenHole
Plot data (X and Y values) for various IPR curves.
15
0