├── app.yaml ├── requirements.txt ├── README.md ├── templates ├── includes │ ├── _messages.html │ └── _navbar.html ├── contributors.html ├── layout.html ├── home.html ├── production.html ├── injection.html └── drilling.html ├── main.py ├── LICENSE ├── production.py ├── injection.py └── drilling.py /app.yaml: -------------------------------------------------------------------------------- 1 | runtime: python37 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask 2 | bokeh 3 | pwptemp 4 | gunicorn -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pwptemp web app 2 | Application for visualizing results using pwptemp. 3 | 4 | This webapp is currently not being maintained. Please check this repo [opensource_apps](https://github.com/pro-well-plan/opensource_apps) instead, where we develop an integrated [web application](https://lnkd.in/g2Yr5B9) covering all our existing open-source tools. 5 | -------------------------------------------------------------------------------- /templates/includes/_messages.html: -------------------------------------------------------------------------------- 1 |
2 | {% with messages = get_flashed_messages(with_categories=true) %} 3 | 4 | {% if messages %} 5 | {% for category, message in messages %} 6 | 10 | {% endfor %} 11 | {% endif %} 12 | {% endwith %} 13 |
14 | -------------------------------------------------------------------------------- /templates/contributors.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% block body %} 4 |
5 |

7 |
8 | 9 |
10 | 11 |

Contributors

12 |
13 |

Here you will find of all the people who have contributed to the development of the python tool pwptemp and/or 14 | this web app version:

15 | 21 | 22 |
23 | 24 | {% endblock %} 25 | -------------------------------------------------------------------------------- /templates/includes/_navbar.html: -------------------------------------------------------------------------------- 1 | 26 | -------------------------------------------------------------------------------- /templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | pwptemp web app 4 | 5 | 6 | 7 | 8 | 9 | 10 | {% include 'includes/_navbar.html' %} 11 | 12 |
13 | {% include 'includes/_messages.html' %} 14 | {% block body %}{% endblock %} 15 |
16 | 17 | 18 | 19 | 23 | 28 | 29 | -------------------------------------------------------------------------------- /templates/home.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% block body %} 4 |
5 |

7 |
8 | 9 |
10 |

pwptemp is a small LGPL licensed library for easy calculation of the temperature distribution along the well. 11 | Features are added as they are needed; suggestions and contributions of all kinds are very welcome.

12 |

Check the repo for this web application: pwptemp web app - Github

13 |

Check the repo for the python tool: pwptemp - Github

14 |

Available from the Python Package Index: pwptemp - PyPI

15 | 16 |

For further information contact juan@prowellplan.com


17 |
18 | 19 |
20 | 21 |


22 |
23 | 24 | 25 | {% endblock %} -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template 2 | from drilling import * 3 | from production import * 4 | from injection import * 5 | from bokeh.embed import components 6 | from bokeh.resources import INLINE 7 | 8 | app = Flask(__name__) 9 | app.secret_key = 'random secret' 10 | 11 | 12 | @app.route("/") 13 | def home(): 14 | return render_template("home.html") 15 | 16 | 17 | @app.route("/contributors") 18 | def contributors(): 19 | return render_template("contributors.html") 20 | 21 | 22 | def encode_utf8(u): 23 | """ 24 | Encode a UTF-8 string to a sequence of bytes. 25 | :param u: the string to encode 26 | :return: bytes 27 | """ 28 | import sys 29 | if sys.version_info[0] == 2: 30 | u = u.encode('utf-8') 31 | return u 32 | 33 | 34 | @app.route("/production") 35 | def production(): 36 | p, inputs = define_prod_plot() 37 | 38 | # grab the static resources 39 | js_resources = INLINE.render_js() 40 | css_resources = INLINE.render_css() 41 | 42 | # Embed plot into HTML via Flask Render 43 | script, div = components(p) 44 | html = render_template('production.html', plot_script=script, plot_div=div, js_resources=js_resources, 45 | css_resources=css_resources, time=inputs['time'], depth=inputs['depth'], wd=inputs['wd'], 46 | kop=inputs['kop'], eob=inputs['eob'], build_angle=inputs['build_angle'], kop2=inputs['kop2'], 47 | eob2=inputs['eob2'], sod=inputs['sod'], eod=inputs['eod'], q=inputs['q'], 48 | rhof=inputs['rhof'], rhot=inputs['rhot'], rhoc=inputs['rhoc'], 49 | rhor=inputs['rhor'], rhofm=inputs['rhofm'], rhow=inputs['rhow'], rhocem=inputs['rhocem'], 50 | n_casings=inputs['n_casings'], dro=inputs['dro'], dri=inputs['dri'], 51 | dto=inputs['dto'], dti=inputs['dti'], wtg=inputs['wtg'], gt=inputs['gt']) 52 | 53 | return encode_utf8(html) 54 | 55 | 56 | @app.route("/drilling") 57 | def drilling(): 58 | p, inputs = define_drill_plot() 59 | 60 | # grab the static resources 61 | js_resources = INLINE.render_js() 62 | css_resources = INLINE.render_css() 63 | 64 | # Embed plot into HTML via Flask Render 65 | script, div = components(p) 66 | html = render_template('drilling.html', plot_script=script, plot_div=div, js_resources=js_resources, 67 | css_resources=css_resources, time=inputs['time'], depth=inputs['depth'], wd=inputs['wd'], 68 | kop=inputs['kop'], eob=inputs['eob'], build_angle=inputs['build_angle'], kop2=inputs['kop2'], 69 | eob2=inputs['eob2'], sod=inputs['sod'], eod=inputs['eod'], tin=inputs['tin'], q=inputs['q'], 70 | rpm=inputs['rpm'], tbit=inputs['tbit'], wob=inputs['wob'], rop=inputs['rop'], 71 | an=inputs['an'], rhof=inputs['rhof'], rhod=inputs['rhod'], rhoc=inputs['rhoc'], 72 | rhor=inputs['rhor'], rhofm=inputs['rhofm'], rhow=inputs['rhow'], rhocem=inputs['rhocem'], 73 | n_casings=inputs['n_casings'], dro=inputs['dro'], dri=inputs['dri'], 74 | ddo=inputs['ddo'], ddi=inputs['ddi'], wtg=inputs['wtg'], gt=inputs['gt']) 75 | 76 | return encode_utf8(html) 77 | 78 | 79 | @app.route("/injection") 80 | def injection(): 81 | p, inputs = define_inj_plot() 82 | 83 | # grab the static resources 84 | js_resources = INLINE.render_js() 85 | css_resources = INLINE.render_css() 86 | 87 | # Embed plot into HTML via Flask Render 88 | script, div = components(p) 89 | html = render_template('injection.html', plot_script=script, plot_div=div, js_resources=js_resources, 90 | css_resources=css_resources, time=inputs['time'], depth=inputs['depth'], wd=inputs['wd'], 91 | kop=inputs['kop'], eob=inputs['eob'], build_angle=inputs['build_angle'], kop2=inputs['kop2'], 92 | eob2=inputs['eob2'], sod=inputs['sod'], eod=inputs['eod'], q=inputs['q'], tin=inputs['tin'], 93 | rhof=inputs['rhof'], rhot=inputs['rhot'], rhoc=inputs['rhoc'], rhor=inputs['rhor'], 94 | rhofm=inputs['rhofm'], rhow=inputs['rhow'], rhocem=inputs['rhocem'], 95 | n_casings=inputs['n_casings'], dro=inputs['dro'], dri=inputs['dri'], 96 | dto=inputs['dto'], dti=inputs['dti'], wtg=inputs['wtg'], gt=inputs['gt']) 97 | 98 | return encode_utf8(html) 99 | 100 | 101 | if __name__ == "__main__": 102 | app.run(debug=True) 103 | 104 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /templates/production.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% block body %} 4 | 5 | 6 | 7 | {{ js_resources|indent(4)|safe }} 8 | {{ css_resources|indent(4)|safe }} 9 | {{ plot_script|indent(4)|safe }} 10 | 11 | 12 | 13 | 14 |
15 |

17 |
18 | 19 |
20 | 21 |

pwptemp for production

22 |
23 |

In this section you can generate the well temperature distribution for a production operation. Set the 24 | inputs and click the 'Run' button

25 | 26 |
27 | 28 |
29 | 30 | 31 |
32 | 33 |
34 | 35 | 36 |
37 | 38 |
39 | 40 | - od (in): 41 | - id (in): 42 |
43 | 44 |
45 | 46 |

47 | 48 | - od (in): 49 | - id (in):

50 |

51 | 52 |
53 | 54 |
55 | 56 | 57 | 71 | 72 | 73 | 74 | 75 | 76 |
77 | 78 |

79 |
80 | 81 | 82 | 119 | 120 |
121 | 122 |
123 |
Vertical    124 | J-type    125 | S-type    126 | Horizontal single-curve    127 | Horizontal double-curve

128 | kick-off point (kop, m):    129 | end of build (eob, m):

130 | build angle (°):

131 | kick-off point 2 (kop2, m):    132 | end of build 2 (eob2, m):

133 | start of drop (sod, m):    134 | end of drop (eod, m):

135 |
136 |
137 | 138 |
139 | 140 |
141 |
142 | production rate (m3/d):

143 |
144 |
145 | 146 |
147 | 148 |
149 |
150 | fluid density (sg):    151 | tubing density (sg):

152 | casing density (sg):    153 | riser density (sg):

154 | formation density (sg):    155 | seawater density (sg):

156 | cement density (sg):

157 |
158 |
159 | 160 |
161 | 162 |
163 |
Temperature Distribution
164 | Temperature Behavior
165 | T. Distributions
166 |    Fluid inside the tubing
167 |    Fluid inside the annulus
168 |    Riser wall
169 |    Casing wall
170 |    Formation (Initial)
171 |    Surrounding Space

172 |
173 |
174 | 175 | 191 |

192 | 193 |
194 | 195 | {{ plot_div|indent(4)|safe }}

196 | 197 |

For further information contact juan@prowellplan.com


198 | 199 |
200 | 201 | 202 | 203 | {% endblock %} -------------------------------------------------------------------------------- /templates/injection.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% block body %} 4 | 5 | 6 | 7 | {{ js_resources|indent(4)|safe }} 8 | {{ css_resources|indent(4)|safe }} 9 | {{ plot_script|indent(4)|safe }} 10 | 11 | 12 | 13 | 14 |
15 |

17 |
18 | 19 |
20 | 21 |

pwptemp for injection

22 |
23 |

In this section you can generate the well temperature distribution for a injection operation. Set the 24 | inputs and click the 'Run' button

25 | 26 |
27 | 28 |
29 | 30 | 31 |
32 | 33 |
34 | 35 | 36 |
37 | 38 |
39 | 40 | - od (in): 41 | - id (in): 42 |
43 | 44 |
45 | 46 |

47 | 48 | - od (in): 49 | - id (in):

50 |

51 | 52 |
53 | 54 |
55 | 56 | 57 | 71 | 72 | 73 | 74 | 75 | 76 |
77 | 78 |

79 |
80 | 81 | 82 | 119 | 120 |
121 | 122 |
123 |
Vertical    124 | J-type    125 | S-type    126 | Horizontal single-curve    127 | Horizontal double-curve

128 | kick-off point (kop, m):    129 | end of build (eob, m):

130 | build angle (°):

131 | kick-off point 2 (kop2, m):    132 | end of build 2 (eob2, m):

133 | start of drop (sod, m):    134 | end of drop (eod, m):

135 |
136 |
137 | 138 |
139 | 140 |
141 |
142 | fluid inlet temperature (°C):

143 | injection rate (m3/d):

144 |
145 |
146 | 147 |
148 | 149 |
150 |
151 | fluid density (sg):    152 | tubing density (sg):

153 | casing density (sg):    154 | riser density (sg):

155 | formation density (sg):    156 | seawater density (sg):

157 | cement density (sg):

158 |
159 |
160 | 161 |
162 | 163 |
164 |
Temperature Distribution
165 | Temperature Behavior
166 | T. Distributions
167 |    Fluid inside the tubing
168 |    Fluid inside the annulus
169 |    Riser wall
170 |    Casing wall
171 |    Formation (Initial)
172 |    Surrounding Space

173 |
174 |
175 | 176 | 192 |

193 | 194 |
195 | 196 | {{ plot_div|indent(4)|safe }}

197 | 198 |

For further information contact juan@prowellplan.com


199 | 200 |
201 | 202 | 203 | 204 | {% endblock %} -------------------------------------------------------------------------------- /templates/drilling.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% block body %} 4 | 5 | 6 | 7 | {{ js_resources|indent(4)|safe }} 8 | {{ css_resources|indent(4)|safe }} 9 | {{ plot_script|indent(4)|safe }} 10 | 11 | 12 | 13 | 14 |
15 |

17 |
18 | 19 |
20 | 21 |

pwptemp for drilling

22 |
23 |

In this section you can generate the well temperature distribution for a drilling operation. Set the inputs 24 | and click the 'Run' button

25 | 26 |
27 | 28 |
29 | 30 | 31 |
32 | 33 |
34 | 35 | 36 |
37 | 38 |
39 | 40 | - od (in): 41 | - id (in): 42 |
43 | 44 |
45 | 46 |

47 | 48 | - od (in): 49 | - id (in):

50 |

51 | 52 |
53 | 54 |
55 | 56 | 57 | 71 | 72 | 73 | 74 | 75 | 76 |
77 | 78 |

79 |
80 | 81 | 82 | 119 | 120 |
121 | 122 |
123 |
Vertical    124 | J-type    125 | S-type    126 | Horizontal single-curve    127 | Horizontal double-curve

128 | kick-off point (kop, m):    129 | end of build (eob, m):

130 | build angle (°):

131 | kick-off point 2 (kop2, m):    132 | end of build 2 (eob2, m):

133 | start of drop (sod, m):    134 | end of drop (eod, m):

135 |
136 |
137 | 138 |
139 | 140 |
141 |
142 | fluid inlet temperature (°C):    143 | circulation rate (lpm):

144 | RPM:    145 | torque on the bit (kN*m):    146 | weight on bit (kN):

147 | ROP (m/h):    148 | area of the nozzles (in2):

149 |
150 |
151 | 152 |
153 | 154 |
155 |
156 | fluid density (sg):    157 | drill pipe density (sg):

158 | casing density (sg):    159 | riser density (sg):

160 | formation density (sg):    161 | seawater density (sg):

162 | cement density (sg):

163 |
164 |
165 | 166 |
167 | 168 |
169 |
Temperature Distribution
170 | Temperature Behavior
171 | T. Distributions
172 |    Fluid inside the drill string
173 |    Fluid inside the annulus
174 |    Riser wall
175 |    Casing wall
176 |    Formation (Initial)
177 |    Surrounding Space

178 |
179 |
180 | 181 | 197 |

198 | 199 |
200 | 201 | {{ plot_div|indent(4)|safe }}

202 | 203 |

For further information contact juan@prowellplan.com


204 | 205 |
206 | 207 | 208 | 209 | {% endblock %} -------------------------------------------------------------------------------- /production.py: -------------------------------------------------------------------------------- 1 | from bokeh.plotting import figure 2 | from bokeh.layouts import row 3 | from flask import request, flash 4 | from main import error_messages 5 | from pwptemp.wellpath import get 6 | import pwptemp.production as ptp 7 | 8 | 9 | def define_prod_plot(): 10 | time = request.args.get("time") 11 | depth = request.args.get("depth") 12 | wd = request.args.get("wd") 13 | well_profile = request.args.get("well_profile") 14 | kop = request.args.get("kop") 15 | eob = request.args.get("eob") 16 | build_angle = request.args.get("build_angle") 17 | kop2 = request.args.get("kop2") 18 | eob2 = request.args.get("eob2") 19 | sod = request.args.get("sod") 20 | eod = request.args.get("eod") 21 | plot_type = request.args.get("plot_type") 22 | dt_tft = request.args.get("dt_tft") 23 | dt_ta = request.args.get("dt_ta") 24 | dt_tr = request.args.get("dt_tr") 25 | dt_tc = request.args.get("dt_tc") 26 | dt_tfm = request.args.get("dt_tfm") 27 | dt_tsr = request.args.get("dt_tsr") 28 | 29 | # TUBULAR 30 | n_casings = request.args.get("n_casings") 31 | dro = request.args.get("dro") 32 | dri = request.args.get("dri") 33 | dto = request.args.get("dto") 34 | dti = request.args.get("dti") 35 | 36 | # OPERATIONAL PARAMETERS 37 | q = request.args.get("q") 38 | 39 | # DENSITIES 40 | rhof = request.args.get("rhof") 41 | rhot = request.args.get("rhot") 42 | rhoc = request.args.get("rhoc") 43 | rhor = request.args.get("rhor") 44 | rhofm = request.args.get("rhofm") 45 | rhow = request.args.get("rhow") 46 | rhocem = request.args.get("rhocem") 47 | 48 | wtg = request.args.get("wtg") 49 | gt = request.args.get("gt") 50 | 51 | if time is None: 52 | time = 2 53 | depth = 3000 54 | wd = 150 55 | well_profile = "V" 56 | kop = 600 57 | eob = 1500 58 | build_angle = 40 59 | kop2 = 1800 60 | eob2 = 2300 61 | sod = 2000 62 | eod = 2600 63 | plot_type = 1 64 | dt_tft = True 65 | dt_ta = False 66 | dt_tr = False 67 | dt_tc = False 68 | dt_tfm = True 69 | dt_tsr = False 70 | n_casings = 0 71 | 72 | # TUBULAR 73 | casings_list = [] 74 | dro = 21 75 | dri = 17.716 76 | dto = 4.5 77 | dti = 4 78 | 79 | # OPERATIONAL PARAMETERS 80 | q = 2000 # production rate, 2000 m3/d 81 | 82 | # DENSITIES 83 | rhof = 0.85 # production fluid density, sg 84 | rhot = 7.6 85 | rhoc = 7.8 86 | rhor = 7.8 87 | rhofm = 2.245 88 | rhow = 1.029 89 | rhocem = 2.7 90 | 91 | wtg = -0.005 92 | gt = 0.0238 93 | 94 | else: 95 | time = float(time) 96 | depth = float(depth) 97 | wd = float(wd) 98 | well_profile = str(well_profile) 99 | kop = float(kop) 100 | eob = float(eob) 101 | build_angle = int(build_angle) 102 | kop2 = float(kop2) 103 | eob2 = float(eob2) 104 | sod = float(sod) 105 | eod = float(eod) 106 | plot_type = int(plot_type) 107 | dt_tft = bool(dt_tft) 108 | dt_ta = bool(dt_ta) 109 | dt_tr = bool(dt_tr) 110 | dt_tc = bool(dt_tc) 111 | dt_tfm = bool(dt_tfm) 112 | dt_tsr = bool(dt_tsr) 113 | n_casings = int(n_casings) 114 | 115 | # TUBULAR 116 | casings_list = [] 117 | for i in range(1, n_casings + 1): 118 | csg_dict = {"od": float(request.args.get("od" + str(i))), "id": float(request.args.get("id" + str(i))), 119 | "depth": float(request.args.get("depth" + str(i)))} 120 | casings_list.append(csg_dict) 121 | dro = float(dro) 122 | dri = float(dri) 123 | dto = float(dto) 124 | dti = float(dti) 125 | 126 | # OPERATIONAL PARAMETERS 127 | q = float(q) 128 | 129 | # DENSITIES 130 | rhof = float(rhof) 131 | rhot = float(rhot) 132 | rhoc = float(rhoc) 133 | rhor = float(rhor) 134 | rhofm = float(rhofm) 135 | rhow = float(rhow) 136 | rhocem = float(rhocem) 137 | 138 | wtg = float(wtg) 139 | gt = float(gt) 140 | 141 | inputs = {'time': time, 'depth': depth, 'wd': wd, 'well_profile': well_profile, 'kop': kop, 'eob': eob, 142 | 'build_angle': build_angle, 'kop2': kop2, 'eob2': eob2, 'sod': sod, 'eod': eod, 'plot_type': plot_type, 143 | 'n_casings': n_casings} 144 | 145 | # Others parameters: the ones which should be used for the attribute 'change_inputs' 146 | others = {'wd': wd, 'q': q, 'rhof': rhof, 'rhot': rhot, 'rhoc': rhoc, 'rhor': rhor, 'rhofm': rhofm, 'rhow': rhow, 147 | 'rhocem': rhocem, 'dro': dro, 'dri': dri, 'dto': dto, 'dti': dti, 'wtg': wtg, 'gt': gt} 148 | 149 | inputs.update(others) # Merge 'others' into the 'inputs' dictionary 150 | 151 | error_raised = error_messages(inputs) # Checking process for warning messages depending on the inputs 152 | 153 | if error_raised == 0: 154 | if plot_type != 5: 155 | temp = ptp.temp(time, mdt=depth, casings=casings_list, profile=well_profile, change_input=others, 156 | build_angle=build_angle, kop=kop, eob=eob, kop2=kop2, eob2=eob2, sod=sod, eod=eod) 157 | 158 | if plot_type == 1: 159 | fig1 = create_figure1(temp) 160 | if plot_type == 4: 161 | fig1 = create_figure4(temp.behavior()) 162 | if plot_type == 5: 163 | temp = ptp.temp(time, mdt=depth, log=True, profile=well_profile, change_input=others, 164 | build_angle=build_angle, kop=kop, eob=eob, kop2=kop2, eob2=eob2, sod=sod, eod=eod) 165 | fig1 = create_figure5(temp, tft=dt_tft, ta=dt_ta, tr=dt_tr, tc=dt_tc, tfm=dt_tfm, tsr=dt_tsr) 166 | 167 | wellpath = get(depth, profile=well_profile, build_angle=build_angle, kop=kop, eob=eob, kop2=kop2, 168 | eob2=eob2, sod=sod, eod=eod) 169 | fig2 = plot_wellpath(wellpath) 170 | 171 | p = row(fig2, fig1) 172 | 173 | else: 174 | p = figure(sizing_mode='stretch_both') 175 | 176 | return p, inputs 177 | 178 | 179 | def plot_wellpath(wellpath): 180 | p = figure(sizing_mode='stretch_both') 181 | p.line(wellpath.north, wellpath.tvd, line_color='blue') 182 | p.xaxis.axis_label = 'North, m' 183 | p.yaxis.axis_label = 'TVD, m' 184 | p.title.text = 'Well Profile' 185 | p.y_range.flipped = True # reversing y axis 186 | p.toolbar.active_drag = None # disable drag by default 187 | return p 188 | 189 | 190 | def create_figure1(temp, sr=False): 191 | p = figure(sizing_mode='stretch_both') 192 | md = temp.md 193 | riser = temp.riser 194 | tr = [i for i in temp.tr if i] 195 | csg = temp.csgs_reach 196 | tc = [i for i in temp.tc if i] 197 | p.line(temp.tft, md, line_color='red', legend_label='Fluid in Tubing') # Temp. inside Tubing vs Depth 198 | p.line(temp.ta, md, line_color='blue', legend_label='Fluid in Annulus') 199 | if riser > 0: 200 | p.line(tr, md, line_color='green', legend_label='Riser') # Temp. due to gradient vs Depth 201 | if csg > 0: 202 | p.line(tc, md, line_color='orange', legend_label='Casing') # Temp. due to gradient vs Depth 203 | p.line(temp.tfm, md, line_color='darkred', legend_label='Formation') # Temp. due to gradient vs Depth 204 | if sr: 205 | # Temp. due to gradient vs Depth 206 | p.line(temp.tsr, md, line_color='salmon', ls='-', marker='', legend_label='Surrounding Space') 207 | 208 | p.xaxis.axis_label = 'Temperature, °C' 209 | p.yaxis.axis_label = 'MD, m' 210 | p.title.text = 'Temperature Profile at %1.1f hours' % temp.time 211 | p.y_range.flipped = True # reversing y axis 212 | p.toolbar.active_drag = None # disable drag by default 213 | return p 214 | 215 | 216 | def create_figure4(behavior): 217 | p = figure(sizing_mode='stretch_both') 218 | time = int(behavior.finaltime) 219 | p.line(range(time), behavior.tout, line_color='red', legend_label='Outlet (Tubing)') # Temp. outlet vs Time 220 | # Formation Temp. vs Time 221 | p.line(range(time), [behavior.tfm[-1]] * len(behavior.tout), line_color='black', legend_label='Formation') 222 | p.xaxis.axis_label = 'Time, h' 223 | p.yaxis.axis_label = 'Temperature, °C' 224 | p.title.text = 'Temperature behavior (%1.1f hours)' % behavior.finaltime 225 | p.toolbar.active_drag = None # disable drag by default 226 | return p 227 | 228 | 229 | def create_figure5(temp, tft=True, ta=False, tr=False, tc=False, tfm=True, tsr=False): 230 | values = temp.temp_log 231 | times = [x for x in temp.time_log] 232 | 233 | if temp.time > 5: 234 | first_quarter = int(len(values) / 3) 235 | second_quarter = int(len(values) / 3) * 2 236 | values = [values[0], values[first_quarter], values[second_quarter], values[-1]] 237 | times = [times[0], times[first_quarter], times[second_quarter], times[-1]] 238 | 239 | p = figure(sizing_mode='stretch_both') 240 | md = temp.md 241 | riser = temp.riser 242 | csg = temp.csgs_reach 243 | base = ['red', 'blue', 'green', 'orange', 'olive', 'powderblue', 'salmon', 'goldenrod', 'chocolate', 'cadetblue'] 244 | color = [] 245 | for i in range(2): 246 | color += base 247 | if tfm: 248 | p.line(temp.tfm, md, line_color='black', legend_label='Formation - Initial') # Temp. due to gradient vs Depth 249 | if len(values) > len(color): 250 | color = color * round((len(values) / len(color))) 251 | for x in range(len(values)): 252 | # Plotting Temperature PROFILE 253 | if tft: 254 | p.line(values[x].tft, md, line_color=color[x], legend_label='Fluid in Tubing at %1.1f hours' % times[x]) 255 | if ta: 256 | p.line(values[x].ta, md, line_color=color[x+len(values)], legend_label='Fluid in Annulus at %1.1f hours' % times[x]) 257 | if riser > 0 and tr: 258 | tr = [i for i in values[x].tr if i] 259 | p.line(tr, md, line_color=color[x+len(values)*2], legend_label='Riser at %1.1f hours' % times[x]) 260 | if csg > 0 and tc: 261 | tcsg_list = [i for i in values[x].tc if i] 262 | p.line(tcsg_list, md, line_color=color[x+len(values)*2], legend_label='Casing at %1.1f hours' % times[x]) 263 | if tsr: 264 | # Temp. due to gradient vs Depth 265 | p.line(values[x].tsr, md, line_color=color[x], legend_label='Surrounding Space') 266 | p.xaxis.axis_label = 'Temperature, °C' 267 | p.yaxis.axis_label = 'Depth, m' 268 | p.title.text = 'Temperature Profiles' 269 | p.y_range.flipped = True # reversing y axis 270 | p.toolbar.active_drag = None # disable drag by default 271 | return p 272 | 273 | 274 | def error_messages(inputs): 275 | 276 | error_raised = 0 277 | if inputs['wd'] > inputs['depth']: 278 | flash('water depth is higher than the total depth', 'danger') 279 | error_raised = 1 280 | 281 | if inputs['well_profile'] == "J" or inputs['well_profile'] == "H1": 282 | 283 | if inputs['kop'] > inputs['depth']: 284 | flash('kop is higher than the total depth', 'danger') 285 | error_raised = 1 286 | 287 | if inputs['eob'] > inputs['depth']: 288 | flash('eob is higher than the total depth', 'danger') 289 | error_raised = 1 290 | 291 | if inputs['eob'] < inputs['kop']: 292 | flash('eob must be deeper than kop', 'danger') 293 | error_raised = 1 294 | 295 | if inputs['well_profile'] == "S": 296 | 297 | if inputs['sod'] > inputs['depth']: 298 | flash('sod is higher than the total depth', 'danger') 299 | error_raised = 1 300 | 301 | if inputs['eod'] > inputs['depth']: 302 | flash('eod is higher than the total depth', 'danger') 303 | error_raised = 1 304 | 305 | if inputs['eod'] < inputs['sod']: 306 | flash('eob2 must be deeper than kop2', 'danger') 307 | error_raised = 1 308 | 309 | if inputs['well_profile'] == "H2": 310 | 311 | if inputs['kop2'] > inputs['depth']: 312 | flash('kop2 is higher than the total depth', 'danger') 313 | error_raised = 1 314 | 315 | if inputs['eob2'] > inputs['depth']: 316 | flash('eob2 is higher than the total depth', 'danger') 317 | error_raised = 1 318 | 319 | if inputs['eob2'] < inputs['kop2']: 320 | flash('eob2 must be deeper than kop2', 'danger') 321 | error_raised = 1 322 | 323 | return error_raised -------------------------------------------------------------------------------- /injection.py: -------------------------------------------------------------------------------- 1 | from bokeh.plotting import figure 2 | from bokeh.layouts import row 3 | from flask import request, flash 4 | from main import error_messages 5 | from pwptemp.wellpath import get 6 | import pwptemp.injection as pti 7 | 8 | 9 | def define_inj_plot(): 10 | time = request.args.get("time") 11 | depth = request.args.get("depth") 12 | wd = request.args.get("wd") 13 | well_profile = request.args.get("well_profile") 14 | kop = request.args.get("kop") 15 | eob = request.args.get("eob") 16 | build_angle = request.args.get("build_angle") 17 | kop2 = request.args.get("kop2") 18 | eob2 = request.args.get("eob2") 19 | sod = request.args.get("sod") 20 | eod = request.args.get("eod") 21 | plot_type = request.args.get("plot_type") 22 | dt_tft = request.args.get("dt_tft") 23 | dt_ta = request.args.get("dt_ta") 24 | dt_tr = request.args.get("dt_tr") 25 | dt_tc = request.args.get("dt_tc") 26 | dt_tfm = request.args.get("dt_tfm") 27 | dt_tsr = request.args.get("dt_tsr") 28 | 29 | # TUBULAR 30 | n_casings = request.args.get("n_casings") 31 | dro = request.args.get("dro") 32 | dri = request.args.get("dri") 33 | dto = request.args.get("dto") 34 | dti = request.args.get("dti") 35 | 36 | # OPERATIONAL PARAMETERS 37 | tin = request.args.get("tin") 38 | q = request.args.get("q") 39 | 40 | # DENSITIES 41 | rhof = request.args.get("rhof") 42 | rhot = request.args.get("rhot") 43 | rhoc = request.args.get("rhoc") 44 | rhor = request.args.get("rhor") 45 | rhofm = request.args.get("rhofm") 46 | rhow = request.args.get("rhow") 47 | rhocem = request.args.get("rhocem") 48 | 49 | wtg = request.args.get("wtg") 50 | gt = request.args.get("gt") 51 | 52 | if time is None: 53 | time = 2 54 | depth = 3000 55 | wd = 150 56 | well_profile = "V" 57 | kop = 600 58 | eob = 1500 59 | build_angle = 40 60 | kop2 = 1800 61 | eob2 = 2300 62 | sod = 2000 63 | eod = 2600 64 | plot_type = 1 65 | dt_tft = True 66 | dt_ta = False 67 | dt_tr = False 68 | dt_tc = False 69 | dt_tfm = True 70 | dt_tsr = False 71 | n_casings = 0 72 | 73 | # TUBULAR 74 | casings_list = [] 75 | dro = 21 76 | dri = 17.716 77 | dto = 4.5 78 | dti = 4 79 | 80 | # OPERATIONAL PARAMETERS 81 | tin = 20 82 | q = 144 # injection rate, m3/d 83 | 84 | # DENSITIES 85 | rhof = 1.198 # injection fluid density, sg 86 | rhot = 7.6 87 | rhoc = 7.8 88 | rhor = 7.8 89 | rhofm = 2.245 90 | rhow = 1.029 91 | rhocem = 2.7 92 | 93 | wtg = -0.005 94 | gt = 0.0238 95 | 96 | else: 97 | time = float(time) 98 | depth = float(depth) 99 | wd = float(wd) 100 | well_profile = str(well_profile) 101 | kop = float(kop) 102 | eob = float(eob) 103 | build_angle = int(build_angle) 104 | kop2 = float(kop2) 105 | eob2 = float(eob2) 106 | sod = float(sod) 107 | eod = float(eod) 108 | plot_type = int(plot_type) 109 | dt_tft = bool(dt_tft) 110 | dt_ta = bool(dt_ta) 111 | dt_tr = bool(dt_tr) 112 | dt_tc = bool(dt_tc) 113 | dt_tfm = bool(dt_tfm) 114 | dt_tsr = bool(dt_tsr) 115 | n_casings = int(n_casings) 116 | 117 | # TUBULAR 118 | casings_list = [] 119 | for i in range(1, n_casings + 1): 120 | csg_dict = {"od": float(request.args.get("od" + str(i))), "id": float(request.args.get("id" + str(i))), 121 | "depth": float(request.args.get("depth" + str(i)))} 122 | casings_list.append(csg_dict) 123 | dro = float(dro) 124 | dri = float(dri) 125 | dto = float(dto) 126 | dti = float(dti) 127 | 128 | # OPERATIONAL PARAMETERS 129 | tin = float(tin) 130 | q = float(q) 131 | 132 | # DENSITIES 133 | rhof = float(rhof) 134 | rhot = float(rhot) 135 | rhoc = float(rhoc) 136 | rhor = float(rhor) 137 | rhofm = float(rhofm) 138 | rhow = float(rhow) 139 | rhocem = float(rhocem) 140 | 141 | wtg = float(wtg) 142 | gt = float(gt) 143 | 144 | inputs = {'time': time, 'depth': depth, 'wd': wd, 'well_profile': well_profile, 'kop': kop, 'eob': eob, 145 | 'build_angle': build_angle, 'kop2': kop2, 'eob2': eob2, 'sod': sod, 'eod': eod, 'plot_type': plot_type, 146 | 'n_casings': n_casings} 147 | 148 | # Others parameters: the ones which should be used for the attribute 'change_inputs' 149 | others = {'wd': wd, 'q': q, 'tin': tin, 'rhof': rhof, 'rhot': rhot, 'rhoc': rhoc, 'rhor': rhor, 'rhofm': rhofm, 150 | 'rhow': rhow, 'rhocem': rhocem, 'dro': dro, 'dri': dri, 'dto': dto, 'dti': dti, 'wtg': wtg, 'gt': gt} 151 | 152 | inputs.update(others) # Merge 'others' into the 'inputs' dictionary 153 | 154 | error_raised = error_messages(inputs) # Checking process for warning messages depending on the inputs 155 | 156 | if error_raised == 0: 157 | if plot_type != 5: 158 | temp = pti.temp(time, mdt=depth, casings=casings_list, profile=well_profile, change_input=others, 159 | build_angle=build_angle, kop=kop, eob=eob, kop2=kop2, eob2=eob2, sod=sod, eod=eod) 160 | 161 | if plot_type == 1: 162 | fig1 = create_figure1(temp) 163 | if plot_type == 4: 164 | fig1 = create_figure4(temp.behavior()) 165 | if plot_type == 5: 166 | temp = pti.temp(time, mdt=depth, log=True, profile=well_profile, change_input=others, 167 | build_angle=build_angle, kop=kop, eob=eob, kop2=kop2, eob2=eob2, sod=sod, eod=eod) 168 | fig1 = create_figure5(temp, tft=dt_tft, ta=dt_ta, tr=dt_tr, tc=dt_tc, tfm=dt_tfm, tsr=dt_tsr) 169 | 170 | wellpath = get(depth, profile=well_profile, build_angle=build_angle, kop=kop, eob=eob, kop2=kop2, 171 | eob2=eob2, sod=sod, eod=eod) 172 | fig2 = plot_wellpath(wellpath) 173 | 174 | p = row(fig2, fig1) 175 | 176 | else: 177 | p = figure(sizing_mode='stretch_both') 178 | 179 | return p, inputs 180 | 181 | 182 | def plot_wellpath(wellpath): 183 | p = figure(sizing_mode='stretch_both') 184 | p.line(wellpath.north, wellpath.tvd, line_color='blue') 185 | p.xaxis.axis_label = 'North, m' 186 | p.yaxis.axis_label = 'TVD, m' 187 | p.title.text = 'Well Profile' 188 | p.y_range.flipped = True # reversing y axis 189 | p.toolbar.active_drag = None # disable drag by default 190 | return p 191 | 192 | 193 | def create_figure1(temp, sr=False): 194 | p = figure(sizing_mode='stretch_both') 195 | md = temp.md 196 | riser = temp.riser 197 | tr = [i for i in temp.tr if i] 198 | csg = temp.csgs_reach 199 | tc = [i for i in temp.tc if i] 200 | p.line(temp.tft, md, line_color='red', legend_label='Fluid in Tubing') # Temp. inside Tubing vs Depth 201 | p.line(temp.ta, md, line_color='blue', legend_label='Fluid in Annulus') 202 | if riser > 0: 203 | p.line(tr, md, line_color='green', legend_label='Riser') # Temp. due to gradient vs Depth 204 | if csg > 0: 205 | p.line(tc, md, line_color='orange', legend_label='Casing') # Temp. due to gradient vs Depth 206 | p.line(temp.tfm, md, line_color='darkred', legend_label='Formation') # Temp. due to gradient vs Depth 207 | if sr: 208 | # Temp. due to gradient vs Depth 209 | p.line(temp.tsr, md, line_color='salmon', ls='-', marker='', legend_label='Surrounding Space') 210 | 211 | p.xaxis.axis_label = 'Temperature, °C' 212 | p.yaxis.axis_label = 'MD, m' 213 | p.title.text = 'Temperature Profile at %1.1f hours' % temp.time 214 | p.y_range.flipped = True # reversing y axis 215 | p.toolbar.active_drag = None # disable drag by default 216 | return p 217 | 218 | 219 | def create_figure4(behavior): 220 | p = figure(sizing_mode='stretch_both') 221 | time = int(behavior.finaltime) 222 | p.line(range(time), behavior.tout, line_color='red', legend_label='Outlet (Tubing)') # Temp. outlet vs Time 223 | # Formation Temp. vs Time 224 | p.line(range(time), [behavior.tfm[-1]] * len(behavior.tout), line_color='black', legend_label='Formation') 225 | p.xaxis.axis_label = 'Time, h' 226 | p.yaxis.axis_label = 'Temperature, °C' 227 | p.title.text = 'Temperature behavior (%1.1f hours)' % behavior.finaltime 228 | p.toolbar.active_drag = None # disable drag by default 229 | return p 230 | 231 | 232 | def create_figure5(temp, tft=True, ta=False, tr=False, tc=False, tfm=True, tsr=False): 233 | values = temp.temp_log 234 | times = [x for x in temp.time_log] 235 | 236 | if temp.time > 5: 237 | first_quarter = int(len(values) / 3) 238 | second_quarter = int(len(values) / 3) * 2 239 | values = [values[0], values[first_quarter], values[second_quarter], values[-1]] 240 | times = [times[0], times[first_quarter], times[second_quarter], times[-1]] 241 | 242 | p = figure(sizing_mode='stretch_both') 243 | md = temp.md 244 | riser = temp.riser 245 | csg = temp.csgs_reach 246 | base = ['red', 'blue', 'green', 'orange', 'olive', 'powderblue', 'salmon', 'goldenrod', 'chocolate', 'cadetblue'] 247 | color = [] 248 | for i in range(2): 249 | color += base 250 | if tfm: 251 | p.line(temp.tfm, md, line_color='black', legend_label='Formation - Initial') # Temp. due to gradient vs Depth 252 | if len(values) > len(color): 253 | color = color * round((len(values) / len(color))) 254 | for x in range(len(values)): 255 | # Plotting Temperature PROFILE 256 | if tft: 257 | p.line(values[x].tft, md, line_color=color[x], legend_label='Fluid in Tubing at %1.1f hours' % times[x]) 258 | if ta: 259 | p.line(values[x].ta, md, line_color=color[x+len(values)], legend_label='Fluid in Annulus at %1.1f hours' % times[x]) 260 | if riser > 0 and tr: 261 | tr = [i for i in values[x].tr if i] 262 | p.line(tr, md, line_color=color[x+len(values)*2], legend_label='Riser at %1.1f hours' % times[x]) 263 | if csg > 0 and tc: 264 | tcsg_list = [i for i in values[x].tc if i] 265 | p.line(tcsg_list, md, line_color=color[x+len(values)*2], legend_label='Casing at %1.1f hours' % times[x]) 266 | if tsr: 267 | # Temp. due to gradient vs Depth 268 | p.line(values[x].tsr, md, line_color=color[x], legend_label='Surrounding Space') 269 | p.xaxis.axis_label = 'Temperature, °C' 270 | p.yaxis.axis_label = 'Depth, m' 271 | p.title.text = 'Temperature Profiles' 272 | p.y_range.flipped = True # reversing y axis 273 | p.toolbar.active_drag = None # disable drag by default 274 | return p 275 | 276 | 277 | def error_messages(inputs): 278 | 279 | error_raised = 0 280 | if inputs['wd'] > inputs['depth']: 281 | flash('water depth is higher than the total depth', 'danger') 282 | error_raised = 1 283 | 284 | if inputs['well_profile'] == "J" or inputs['well_profile'] == "H1": 285 | 286 | if inputs['kop'] > inputs['depth']: 287 | flash('kop is higher than the total depth', 'danger') 288 | error_raised = 1 289 | 290 | if inputs['eob'] > inputs['depth']: 291 | flash('eob is higher than the total depth', 'danger') 292 | error_raised = 1 293 | 294 | if inputs['eob'] < inputs['kop']: 295 | flash('eob must be deeper than kop', 'danger') 296 | error_raised = 1 297 | 298 | if inputs['well_profile'] == "S": 299 | 300 | if inputs['sod'] > inputs['depth']: 301 | flash('sod is higher than the total depth', 'danger') 302 | error_raised = 1 303 | 304 | if inputs['eod'] > inputs['depth']: 305 | flash('eod is higher than the total depth', 'danger') 306 | error_raised = 1 307 | 308 | if inputs['eod'] < inputs['sod']: 309 | flash('eob2 must be deeper than kop2', 'danger') 310 | error_raised = 1 311 | 312 | if inputs['well_profile'] == "H2": 313 | 314 | if inputs['kop2'] > inputs['depth']: 315 | flash('kop2 is higher than the total depth', 'danger') 316 | error_raised = 1 317 | 318 | if inputs['eob2'] > inputs['depth']: 319 | flash('eob2 is higher than the total depth', 'danger') 320 | error_raised = 1 321 | 322 | if inputs['eob2'] < inputs['kop2']: 323 | flash('eob2 must be deeper than kop2', 'danger') 324 | error_raised = 1 325 | 326 | return error_raised -------------------------------------------------------------------------------- /drilling.py: -------------------------------------------------------------------------------- 1 | from bokeh.plotting import figure 2 | from bokeh.layouts import row 3 | from flask import request, flash 4 | from pwptemp.wellpath import get 5 | import pwptemp.drilling as ptd 6 | 7 | 8 | def define_drill_plot(): 9 | time = request.args.get("time") 10 | depth = request.args.get("depth") 11 | wd = request.args.get("wd") 12 | well_profile = request.args.get("well_profile") 13 | kop = request.args.get("kop") 14 | eob = request.args.get("eob") 15 | build_angle = request.args.get("build_angle") 16 | kop2 = request.args.get("kop2") 17 | eob2 = request.args.get("eob2") 18 | sod = request.args.get("sod") 19 | eod = request.args.get("eod") 20 | plot_type = request.args.get("plot_type") 21 | dt_tdsi = request.args.get("dt_tdsi") 22 | dt_ta = request.args.get("dt_ta") 23 | dt_tr = request.args.get("dt_tr") 24 | dt_tcsg = request.args.get("dt_tcsg") 25 | dt_tfm = request.args.get("dt_tfm") 26 | dt_tsr = request.args.get("dt_tsr") 27 | 28 | # TUBULAR 29 | n_casings = request.args.get("n_casings") 30 | dro = request.args.get("dro") 31 | dri = request.args.get("dri") 32 | ddo = request.args.get("ddo") 33 | ddi = request.args.get("ddi") 34 | 35 | # OPERATIONAL PARAMETERS 36 | tin = request.args.get("tin") 37 | q = request.args.get("q") 38 | rpm = request.args.get("rpm") 39 | tbit = request.args.get("tbit") 40 | wob = request.args.get("wob") 41 | rop = request.args.get("rop") 42 | an = request.args.get("an") 43 | 44 | # DENSITIES 45 | rhof = request.args.get("rhof") 46 | rhod = request.args.get("rhod") 47 | rhoc = request.args.get("rhoc") 48 | rhor = request.args.get("rhor") 49 | rhofm = request.args.get("rhofm") 50 | rhow = request.args.get("rhow") 51 | rhocem = request.args.get("rhocem") 52 | 53 | wtg = request.args.get("wtg") 54 | gt = request.args.get("gt") 55 | 56 | if time is None: 57 | time = 2 58 | depth = 3000 59 | wd = 150 60 | well_profile = "V" 61 | kop = 600 62 | eob = 1500 63 | build_angle = 40 64 | kop2 = 1800 65 | eob2 = 2300 66 | sod = 2000 67 | eod = 2600 68 | plot_type = 1 69 | dt_tdsi = True 70 | dt_ta = False 71 | dt_tr = False 72 | dt_tcsg = False 73 | dt_tfm = True 74 | dt_tsr = False 75 | n_casings = 0 76 | 77 | # TUBULAR 78 | casings_list = [] 79 | dro = 21 80 | dri = 17.716 81 | ddo = 4.5 82 | ddi = 4 83 | 84 | # OPERATIONAL PARAMETERS 85 | tin = 20 86 | q = 794.933 87 | rpm = 100 88 | tbit = 1.35 89 | wob = 22.41 90 | rop = 14.4 91 | an = 3100 92 | 93 | # DENSITIES 94 | rhof = 1.198 95 | rhod = 7.6 96 | rhoc = 7.8 97 | rhor = 7.8 98 | rhofm = 2.245 99 | rhow = 1.029 100 | rhocem = 2.7 101 | 102 | wtg = -0.005 103 | gt = 0.0238 104 | 105 | else: 106 | time = float(time) 107 | depth = float(depth) 108 | wd = float(wd) 109 | well_profile = str(well_profile) 110 | kop = float(kop) 111 | eob = float(eob) 112 | build_angle = int(build_angle) 113 | kop2 = float(kop2) 114 | eob2 = float(eob2) 115 | sod = float(sod) 116 | eod = float(eod) 117 | plot_type = int(plot_type) 118 | dt_tdsi = bool(dt_tdsi) 119 | dt_ta = bool(dt_ta) 120 | dt_tr = bool(dt_tr) 121 | dt_tcsg = bool(dt_tcsg) 122 | dt_tfm = bool(dt_tfm) 123 | dt_tsr = bool(dt_tsr) 124 | n_casings = int(n_casings) 125 | 126 | # TUBULAR 127 | casings_list = [] 128 | for i in range(1, n_casings + 1): 129 | csg_dict = {"od": float(request.args.get("od" + str(i))), "id": float(request.args.get("id" + str(i))), 130 | "depth": float(request.args.get("depth" + str(i)))} 131 | casings_list.append(csg_dict) 132 | dro = float(dro) 133 | dri = float(dri) 134 | ddo = float(ddo) 135 | ddi = float(ddi) 136 | 137 | # OPERATIONAL PARAMETERS 138 | tin = float(tin) 139 | q = float(q) 140 | rpm = float(rpm) 141 | tbit = float(tbit) 142 | wob = float(wob) 143 | rop = float(rop) 144 | an = float(an) 145 | 146 | # DENSITIES 147 | rhof = float(rhof) 148 | rhod = float(rhod) 149 | rhoc = float(rhoc) 150 | rhor = float(rhor) 151 | rhofm = float(rhofm) 152 | rhow = float(rhow) 153 | rhocem = float(rhocem) 154 | 155 | wtg = float(wtg) 156 | gt = float(gt) 157 | 158 | inputs = {'time': time, 'depth': depth, 'wd': wd, 'well_profile': well_profile, 'kop': kop, 'eob': eob, 159 | 'build_angle': build_angle, 'kop2': kop2, 'eob2': eob2, 'sod': sod, 'eod': eod, 'plot_type': plot_type, 160 | 'n_casings': n_casings} 161 | 162 | # Others parameters: the ones which should be used for the attribute 'change_inputs' 163 | others = {'wd': wd, 'tin': tin, 'q': q, 'rpm': rpm, 'tbit': tbit, 'wob': wob, 'rop': rop, 'an': an, 'rhof': rhof, 164 | 'rhod': rhod, 'rhoc': rhoc, 'rhor': rhor, 'rhofm': rhofm, 'rhow': rhow, 'rhocem': rhocem, 'dro': dro, 165 | 'dri': dri, 'ddo': ddo, 'ddi': ddi, 'wtg': wtg, 'gt': gt} 166 | 167 | inputs.update(others) # Merge 'others' into the 'inputs' dictionary 168 | 169 | error_raised = error_messages(inputs) # Checking process for warning messages depending on the inputs 170 | 171 | if error_raised == 0: 172 | if plot_type != 5: 173 | temp = ptd.temp(time, mdt=depth, casings=casings_list, profile=well_profile, change_input=others, 174 | build_angle=build_angle, kop=kop, eob=eob, kop2=kop2, eob2=eob2, sod=sod, eod=eod) 175 | 176 | if plot_type == 1: 177 | fig1 = create_figure1(temp) 178 | if plot_type == 4: 179 | fig1 = create_figure4(temp.behavior()) 180 | if plot_type == 5: 181 | temp = ptd.temp(time, mdt=depth, log=True, profile=well_profile, change_input=others, 182 | build_angle=build_angle, kop=kop, eob=eob, kop2=kop2, eob2=eob2, sod=sod, eod=eod) 183 | fig1 = create_figure5(temp, tdsi=dt_tdsi, ta=dt_ta, tr=dt_tr, tcsg=dt_tcsg, tfm=dt_tfm, tsr=dt_tsr) 184 | 185 | wellpath = get(depth, profile=well_profile, build_angle=build_angle, kop=kop, eob=eob, kop2=kop2, 186 | eob2=eob2, sod=sod, eod=eod) 187 | fig2 = plot_wellpath(wellpath) 188 | 189 | p = row(fig2, fig1) 190 | 191 | else: 192 | p = figure(sizing_mode='stretch_both') 193 | 194 | return p, inputs 195 | 196 | 197 | def plot_wellpath(wellpath): 198 | p = figure(sizing_mode='stretch_both') 199 | p.line(wellpath.north, wellpath.tvd, line_color='blue') 200 | p.xaxis.axis_label = 'North, m' 201 | p.yaxis.axis_label = 'TVD, m' 202 | p.title.text = 'Well Profile' 203 | p.y_range.flipped = True # reversing y axis 204 | p.toolbar.active_drag = None # disable drag by default 205 | return p 206 | 207 | 208 | def create_figure1(temp, sr=False): 209 | p = figure(sizing_mode='stretch_both') 210 | md = temp.md 211 | riser = temp.riser 212 | tr = [i for i in temp.tr if i] 213 | csg = temp.csgs_reach 214 | tcsg = [i for i in temp.tcsg if i] 215 | p.line(temp.tdsi, md, line_color='red', legend_label='Fluid in Drill String') # Temp. inside Drillpipe vs Depth 216 | p.line(temp.ta, md, line_color='blue', legend_label='Fluid in Annulus') 217 | if riser > 0: 218 | p.line(tr, md, line_color='green', legend_label='Riser') # Temp. due to gradient vs Depth 219 | if csg > 0: 220 | p.line(tcsg, md, line_color='orange', legend_label='Casing') # Temp. due to gradient vs Depth 221 | p.line(temp.tfm, md, line_color='darkred', legend_label='Formation') # Temp. due to gradient vs Depth 222 | if sr: 223 | # Temp. due to gradient vs Depth 224 | p.line(temp.tsr, md, line_color='salmon', ls='-', marker='', legend_label='Surrounding Space') 225 | 226 | p.xaxis.axis_label = 'Temperature, °C' 227 | p.yaxis.axis_label = 'MD, m' 228 | p.title.text = 'Temperature Profile at %1.1f hours' % temp.time 229 | p.y_range.flipped = True # reversing y axis 230 | p.toolbar.active_drag = None # disable drag by default 231 | return p 232 | 233 | 234 | def create_figure4(behavior): 235 | p = figure(sizing_mode='stretch_both') 236 | time = int(behavior.finaltime) 237 | p.line(range(time), behavior.tbot, line_color='blue', legend_label='Bottom') # Temp. outlet vs Time 238 | p.line(range(time), behavior.tout, line_color='red', legend_label='Outlet (Annular)') # Temp. inside Annulus vs Time 239 | p.line(range(time), [behavior.tfm[-1]] * len(behavior.tbot), line_color='black', legend_label='Formation') # Formation Temp. vs Time 240 | p.xaxis.axis_label = 'Time, h' 241 | p.yaxis.axis_label = 'Temperature, °C' 242 | p.title.text = 'Temperature behavior (%1.1f hours)' % behavior.finaltime 243 | p.toolbar.active_drag = None # disable drag by default 244 | return p 245 | 246 | 247 | def create_figure5(temp, tdsi=True, ta=False, tr=False, tcsg=False, tfm=True, tsr=False): 248 | values = temp.temp_log 249 | times = [x for x in temp.time_log] 250 | 251 | if temp.time > 5: 252 | first_quarter = int(len(values) / 3) 253 | second_quarter = int(len(values) / 3) * 2 254 | values = [values[0], values[first_quarter], values[second_quarter], values[-1]] 255 | times = [times[0], times[first_quarter], times[second_quarter], times[-1]] 256 | 257 | p = figure(sizing_mode='stretch_both') 258 | md = temp.md 259 | riser = temp.riser 260 | csg = temp.csgs_reach 261 | base = ['red', 'blue', 'green', 'orange', 'olive', 'powderblue', 'salmon', 'goldenrod', 'chocolate', 'cadetblue'] 262 | color = [] 263 | for i in range(2): 264 | color += base 265 | if tfm: 266 | p.line(temp.tfm, md, line_color='black', legend_label='Formation - Initial') # Temp. due to gradient vs Depth 267 | if len(values) > len(color): 268 | color = color * round((len(values) / len(color))) 269 | for x in range(len(values)): 270 | # Plotting Temperature PROFILE 271 | if tdsi: 272 | p.line(values[x].tdsi, md, line_color=color[x], legend_label='Fluid in Drill String at %1.1f hours' % times[x]) 273 | if ta: 274 | p.line(values[x].ta, md, line_color=color[x+len(values)], legend_label='Fluid in Annulus at %1.1f hours' % times[x]) 275 | if riser > 0 and tr: 276 | tr = [i for i in values[x].tr if i] 277 | p.line(tr, md, line_color=color[x+len(values)*2], legend_label='Riser at %1.1f hours' % times[x]) 278 | if csg > 0 and tcsg: 279 | tcsg_list = [i for i in values[x].tcsg if i] 280 | p.line(tcsg_list, md, line_color=color[x+len(values)*2], legend_label='Casing at %1.1f hours' % times[x]) 281 | if tsr: 282 | # Temp. due to gradient vs Depth 283 | p.line(values[x].tsr, md, line_color=color[x], legend_label='Surrounding Space') 284 | p.xaxis.axis_label = 'Temperature, °C' 285 | p.yaxis.axis_label = 'Depth, m' 286 | p.title.text = 'Temperature Profiles' 287 | p.legend.click_policy = "hide" 288 | p.y_range.flipped = True # reversing y axis 289 | p.toolbar.active_drag = None # disable drag by default 290 | return p 291 | 292 | 293 | def error_messages(inputs): 294 | 295 | error_raised = 0 296 | if inputs['wd'] > inputs['depth']: 297 | flash('water depth is higher than the total depth', 'danger') 298 | error_raised = 1 299 | 300 | if inputs['well_profile'] == "J" or inputs['well_profile'] == "H1": 301 | 302 | if inputs['kop'] > inputs['depth']: 303 | flash('kop is higher than the total depth', 'danger') 304 | error_raised = 1 305 | 306 | if inputs['eob'] > inputs['depth']: 307 | flash('eob is higher than the total depth', 'danger') 308 | error_raised = 1 309 | 310 | if inputs['eob'] < inputs['kop']: 311 | flash('eob must be deeper than kop', 'danger') 312 | error_raised = 1 313 | 314 | if inputs['well_profile'] == "S": 315 | 316 | if inputs['sod'] > inputs['depth']: 317 | flash('sod is higher than the total depth', 'danger') 318 | error_raised = 1 319 | 320 | if inputs['eod'] > inputs['depth']: 321 | flash('eod is higher than the total depth', 'danger') 322 | error_raised = 1 323 | 324 | if inputs['eod'] < inputs['sod']: 325 | flash('eob2 must be deeper than kop2', 'danger') 326 | error_raised = 1 327 | 328 | if inputs['well_profile'] == "H2": 329 | 330 | if inputs['kop2'] > inputs['depth']: 331 | flash('kop2 is higher than the total depth', 'danger') 332 | error_raised = 1 333 | 334 | if inputs['eob2'] > inputs['depth']: 335 | flash('eob2 is higher than the total depth', 'danger') 336 | error_raised = 1 337 | 338 | if inputs['eob2'] < inputs['kop2']: 339 | flash('eob2 must be deeper than kop2', 'danger') 340 | error_raised = 1 341 | 342 | return error_raised 343 | 344 | --------------------------------------------------------------------------------