├── .gitignore ├── 00_add_packages └── 00_add_packages.ipynb ├── 10_jets_basics ├── 01-jets-basics.ipynb ├── 02-distributedjets-basics.ipynb └── 03-common_patterns.ipynb ├── 20_marmousi_model_setup ├── 01_get_marmousi_model.ipynb └── 02_smooth_model.ipynb ├── 30_forward_modeling ├── 01_Wavelets.ipynb ├── 02_ViewModel.ipynb ├── 03_SingleNode.ipynb ├── 04_StaticDistributed.ipynb └── 05_DynamicParallel.ipynb ├── 40_sensitivity ├── 01_SingleTraceSensitivity.ipynb └── 11_WavefieldSeparationSensitivity.ipynb ├── 50_fwi ├── 01_fwi_L2.ipynb ├── 02_fwi_L2_dynamic.ipynb ├── 10_add_slim_packages.ipynb ├── 11_constrained_fwi_pqn.ipynb └── 12_constrained_fwi_spg.ipynb ├── 60_rtm ├── 01_rtm.ipynb └── 02_rtm_DynamicParallel.ipynb ├── LICENSE.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | elastic-marmousi-model.tar.gz 2 | m*.bin 3 | *.segy 4 | elastic-marmousi-model/ 5 | .ipynb_checkpoints 6 | -------------------------------------------------------------------------------- /00_add_packages/00_add_packages.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Add packages\n", 8 | "This notebook will add all the packages used in these demos to your environment. \n", 9 | "\n", 10 | "This includes `SegyIO` from the SLIM group at Georgia Tech [https://slim.gatech.edu](https://slim.gatech.edu).\n", 11 | "\n", 12 | "Note we do not show the routine package management outputs from this notebook." 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": null, 18 | "metadata": {}, 19 | "outputs": [], 20 | "source": [ 21 | "using Pkg\n", 22 | "Pkg.add([\"AzStorage\", \"AzManagers\", \"AzSessions\", \"CloudSeis\", \"DelimitedFiles\", \n", 23 | " \"Distributed\", \"DistributedArrays\", \"DistributedJets\", \"DistributedOperations\", \n", 24 | " \"FFTW\", \"JetPack\", \"JetPackDSP\", \"JetPackTransforms\", \"JetPackWaveFD\", \n", 25 | " \"Jets\", \"LineSearches\", \"LinearAlgebra\", \"Optim\", \"ParallelOperations\", \n", 26 | " \"Printf\", \"PyPlot\", \"Random\", \"SegyIO\", \"Schedulers\", \"TeaSeis\", \"WaveFD\"])\n", 27 | "nothing" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": null, 33 | "metadata": {}, 34 | "outputs": [], 35 | "source": [] 36 | } 37 | ], 38 | "metadata": { 39 | "kernelspec": { 40 | "display_name": "Julia 1.9.3", 41 | "language": "julia", 42 | "name": "julia-1.9" 43 | }, 44 | "language_info": { 45 | "file_extension": ".jl", 46 | "mimetype": "application/julia", 47 | "name": "julia", 48 | "version": "1.9.3" 49 | } 50 | }, 51 | "nbformat": 4, 52 | "nbformat_minor": 4 53 | } 54 | -------------------------------------------------------------------------------- /10_jets_basics/01-jets-basics.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Jets.jl\n", 8 | "The Jets.jl package is a Chevron linear and nonlinear operator framework that is useful for building operators used in inverse problems, such as FWI. \n", 9 | "\n", 10 | "Jets operators are organized into operator packs:\n", 11 | "* `JetPack.jl` padding and truncation, derivatives and integration, permutations and reshaping, and more esoteric operators including transcendental functions \n", 12 | "* `JetPackDSP.jl` digital signal processing including convolution, filtering, and envelopes of signals\n", 13 | "* `JetPackTransforms.jl` slant stack, wavelet, cosine, and Fourier transforms of signals\n", 14 | "* `JetPackWaveFD.jl` seismic modeling operators and Jacobians for use in full waveform inversion " 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "## Add packages used in this group of notebooks to your environment" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 1, 27 | "metadata": {}, 28 | "outputs": [], 29 | "source": [ 30 | "using Jets, JetPack, JetPackTransforms, PyPlot, Random, JetPackDSP, LinearAlgebra" 31 | ] 32 | }, 33 | { 34 | "cell_type": "markdown", 35 | "metadata": {}, 36 | "source": [ 37 | "# JetSpace" 38 | ] 39 | }, 40 | { 41 | "cell_type": "markdown", 42 | "metadata": {}, 43 | "source": [ 44 | "JetSpace is an n-dimensional vector space with additional meta-data. The additional data is:\n", 45 | "* a size (n1,n2,...,np) where prod(n1,n2,...np) = n\n", 46 | "* a element type such as Float32, Float64, ComplexF64, etc." 47 | ] 48 | }, 49 | { 50 | "cell_type": "markdown", 51 | "metadata": {}, 52 | "source": [ 53 | "### Example 1: 10 dimensions, single precision:" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 2, 59 | "metadata": {}, 60 | "outputs": [ 61 | { 62 | "data": { 63 | "text/plain": [ 64 | "JetSpace{Float32,1}((10,))" 65 | ] 66 | }, 67 | "execution_count": 2, 68 | "metadata": {}, 69 | "output_type": "execute_result" 70 | } 71 | ], 72 | "source": [ 73 | "R₁ = JetSpace(Float32,10)" 74 | ] 75 | }, 76 | { 77 | "cell_type": "markdown", 78 | "metadata": {}, 79 | "source": [ 80 | "### Example 2: 200 dimensions, double precision, 10x20 array size" 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "execution_count": 3, 86 | "metadata": {}, 87 | "outputs": [ 88 | { 89 | "data": { 90 | "text/plain": [ 91 | "JetSpace{Float64,2}((10, 20))" 92 | ] 93 | }, 94 | "execution_count": 3, 95 | "metadata": {}, 96 | "output_type": "execute_result" 97 | } 98 | ], 99 | "source": [ 100 | "R₂ = JetSpace(Float64,10,20)" 101 | ] 102 | }, 103 | { 104 | "cell_type": "markdown", 105 | "metadata": {}, 106 | "source": [ 107 | "### Example 3: 400 dimensions, double precision complex, 10x20x2 array size" 108 | ] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "execution_count": 4, 113 | "metadata": {}, 114 | "outputs": [ 115 | { 116 | "data": { 117 | "text/plain": [ 118 | "JetSpace{Complex{Float64},3}((10, 20, 2))" 119 | ] 120 | }, 121 | "execution_count": 4, 122 | "metadata": {}, 123 | "output_type": "execute_result" 124 | } 125 | ], 126 | "source": [ 127 | "R₃ = JetSpace(ComplexF64,10,20,2)" 128 | ] 129 | }, 130 | { 131 | "cell_type": "markdown", 132 | "metadata": {}, 133 | "source": [ 134 | "### Convenience methods\n", 135 | "Given a space, we can use various convenience methods to inspect and use the space." 136 | ] 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": 5, 141 | "metadata": {}, 142 | "outputs": [ 143 | { 144 | "data": { 145 | "text/plain": [ 146 | "Float64" 147 | ] 148 | }, 149 | "execution_count": 5, 150 | "metadata": {}, 151 | "output_type": "execute_result" 152 | } 153 | ], 154 | "source": [ 155 | "eltype(R₂)" 156 | ] 157 | }, 158 | { 159 | "cell_type": "code", 160 | "execution_count": 6, 161 | "metadata": {}, 162 | "outputs": [ 163 | { 164 | "data": { 165 | "text/plain": [ 166 | "2" 167 | ] 168 | }, 169 | "execution_count": 6, 170 | "metadata": {}, 171 | "output_type": "execute_result" 172 | } 173 | ], 174 | "source": [ 175 | "ndims(R₂)" 176 | ] 177 | }, 178 | { 179 | "cell_type": "code", 180 | "execution_count": 7, 181 | "metadata": {}, 182 | "outputs": [ 183 | { 184 | "data": { 185 | "text/plain": [ 186 | "200" 187 | ] 188 | }, 189 | "execution_count": 7, 190 | "metadata": {}, 191 | "output_type": "execute_result" 192 | } 193 | ], 194 | "source": [ 195 | "length(R₂)" 196 | ] 197 | }, 198 | { 199 | "cell_type": "code", 200 | "execution_count": 8, 201 | "metadata": {}, 202 | "outputs": [ 203 | { 204 | "data": { 205 | "text/plain": [ 206 | "(10, 20)" 207 | ] 208 | }, 209 | "execution_count": 8, 210 | "metadata": {}, 211 | "output_type": "execute_result" 212 | } 213 | ], 214 | "source": [ 215 | "size(R₂)" 216 | ] 217 | }, 218 | { 219 | "cell_type": "code", 220 | "execution_count": 9, 221 | "metadata": {}, 222 | "outputs": [ 223 | { 224 | "data": { 225 | "text/plain": [ 226 | "10×20 Array{Float64,2}:\n", 227 | " 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 … 1.0 1.0 1.0 1.0 1.0 1.0 1.0\n", 228 | " 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0\n", 229 | " 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0\n", 230 | " 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0\n", 231 | " 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0\n", 232 | " 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 … 1.0 1.0 1.0 1.0 1.0 1.0 1.0\n", 233 | " 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0\n", 234 | " 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0\n", 235 | " 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0\n", 236 | " 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0" 237 | ] 238 | }, 239 | "execution_count": 9, 240 | "metadata": {}, 241 | "output_type": "execute_result" 242 | } 243 | ], 244 | "source": [ 245 | "reshape(ones(200), R₂)" 246 | ] 247 | }, 248 | { 249 | "cell_type": "code", 250 | "execution_count": 10, 251 | "metadata": {}, 252 | "outputs": [ 253 | { 254 | "data": { 255 | "text/plain": [ 256 | "10×20 Array{Float64,2}:\n", 257 | " 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 … 1.0 1.0 1.0 1.0 1.0 1.0 1.0\n", 258 | " 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0\n", 259 | " 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0\n", 260 | " 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0\n", 261 | " 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0\n", 262 | " 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 … 1.0 1.0 1.0 1.0 1.0 1.0 1.0\n", 263 | " 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0\n", 264 | " 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0\n", 265 | " 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0\n", 266 | " 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0" 267 | ] 268 | }, 269 | "execution_count": 10, 270 | "metadata": {}, 271 | "output_type": "execute_result" 272 | } 273 | ], 274 | "source": [ 275 | "ones(R₂)" 276 | ] 277 | }, 278 | { 279 | "cell_type": "code", 280 | "execution_count": 11, 281 | "metadata": {}, 282 | "outputs": [ 283 | { 284 | "data": { 285 | "text/plain": [ 286 | "10×20 Array{Float64,2}:\n", 287 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 … 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", 288 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", 289 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", 290 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", 291 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", 292 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 … 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", 293 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", 294 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", 295 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", 296 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0" 297 | ] 298 | }, 299 | "execution_count": 11, 300 | "metadata": {}, 301 | "output_type": "execute_result" 302 | } 303 | ], 304 | "source": [ 305 | "zeros(R₂)" 306 | ] 307 | }, 308 | { 309 | "cell_type": "code", 310 | "execution_count": 12, 311 | "metadata": {}, 312 | "outputs": [ 313 | { 314 | "data": { 315 | "text/plain": [ 316 | "10×20 Array{Float64,2}:\n", 317 | " 0.0886562 0.358071 0.496942 … 0.0116482 0.915527 0.772992\n", 318 | " 0.0172601 0.269985 0.186518 0.134234 0.924338 0.0652378\n", 319 | " 0.55527 0.882708 0.556064 0.00500313 0.549915 0.265286\n", 320 | " 0.0441227 0.137385 0.655203 0.677555 0.0450126 0.659201\n", 321 | " 0.41626 0.600819 0.663184 0.247353 0.24793 0.441284\n", 322 | " 0.412157 0.387547 0.359646 … 0.0326728 0.168353 0.32341\n", 323 | " 0.260469 0.520764 0.089421 0.721207 0.129516 0.611746\n", 324 | " 0.873918 0.959408 0.484825 0.683767 0.415674 0.0896736\n", 325 | " 0.803005 0.551427 0.512047 0.752355 0.750637 0.0197654\n", 326 | " 0.859921 0.13708 0.0700897 0.361819 0.253133 0.599527" 327 | ] 328 | }, 329 | "execution_count": 12, 330 | "metadata": {}, 331 | "output_type": "execute_result" 332 | } 333 | ], 334 | "source": [ 335 | "rand(R₂)" 336 | ] 337 | }, 338 | { 339 | "cell_type": "code", 340 | "execution_count": 13, 341 | "metadata": {}, 342 | "outputs": [ 343 | { 344 | "data": { 345 | "text/plain": [ 346 | "10×20 Array{Float64,2}:\n", 347 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 … 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", 348 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", 349 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", 350 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", 351 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", 352 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 … 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", 353 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", 354 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", 355 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", 356 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0" 357 | ] 358 | }, 359 | "execution_count": 13, 360 | "metadata": {}, 361 | "output_type": "execute_result" 362 | } 363 | ], 364 | "source": [ 365 | "Array(R₂)\n", 366 | "# note the values in this returned array are undefined" 367 | ] 368 | }, 369 | { 370 | "cell_type": "markdown", 371 | "metadata": {}, 372 | "source": [ 373 | "# Jet operators" 374 | ] 375 | }, 376 | { 377 | "cell_type": "markdown", 378 | "metadata": {}, 379 | "source": [ 380 | "A Jet operator is a linear or nonlinear mapping between two spaces. In the case of a nonlinear operator, a jet also defines the linearization or Jacobian of the nonlinear mapping.\n", 381 | "\n", 382 | "* A Jet operator encapsulates a Jet\n", 383 | "* A Jet is loosely based on the mathematical name-sake, and includes the mapping and linearization\n", 384 | "\n", 385 | "### See also\n", 386 | "https://en.wikipedia.org/wiki/Jet_(mathematics)" 387 | ] 388 | }, 389 | { 390 | "cell_type": "markdown", 391 | "metadata": {}, 392 | "source": [ 393 | "### Example 1: Linear operator" 394 | ] 395 | }, 396 | { 397 | "cell_type": "code", 398 | "execution_count": 14, 399 | "metadata": {}, 400 | "outputs": [ 401 | { 402 | "data": { 403 | "text/plain": [ 404 | "\"Jet linear operator, (2,) → (2,)\"" 405 | ] 406 | }, 407 | "execution_count": 14, 408 | "metadata": {}, 409 | "output_type": "execute_result" 410 | } 411 | ], 412 | "source": [ 413 | "A = JopDiagonal(rand(2))" 414 | ] 415 | }, 416 | { 417 | "cell_type": "code", 418 | "execution_count": 15, 419 | "metadata": {}, 420 | "outputs": [ 421 | { 422 | "data": { 423 | "text/plain": [ 424 | "(diagonal = [0.30305942757302473, 0.7577301147615294],)" 425 | ] 426 | }, 427 | "execution_count": 15, 428 | "metadata": {}, 429 | "output_type": "execute_result" 430 | } 431 | ], 432 | "source": [ 433 | "state(A)" 434 | ] 435 | }, 436 | { 437 | "cell_type": "code", 438 | "execution_count": 16, 439 | "metadata": {}, 440 | "outputs": [ 441 | { 442 | "data": { 443 | "text/plain": [ 444 | "2×2 Array{Float64,2}:\n", 445 | " 0.303059 0.0\n", 446 | " 0.0 0.75773" 447 | ] 448 | }, 449 | "execution_count": 16, 450 | "metadata": {}, 451 | "output_type": "execute_result" 452 | } 453 | ], 454 | "source": [ 455 | "B = convert(Array,A)" 456 | ] 457 | }, 458 | { 459 | "cell_type": "code", 460 | "execution_count": 17, 461 | "metadata": {}, 462 | "outputs": [ 463 | { 464 | "data": { 465 | "text/plain": [ 466 | "2-element Array{Float64,1}:\n", 467 | " 0.1734545126737037\n", 468 | " 0.16709953594029314" 469 | ] 470 | }, 471 | "execution_count": 17, 472 | "metadata": {}, 473 | "output_type": "execute_result" 474 | } 475 | ], 476 | "source": [ 477 | "# create a random vector in the domain of operator A\n", 478 | "m = rand(domain(A))" 479 | ] 480 | }, 481 | { 482 | "cell_type": "code", 483 | "execution_count": 18, 484 | "metadata": {}, 485 | "outputs": [ 486 | { 487 | "data": { 488 | "text/plain": [ 489 | "2-element Array{Float64,1}:\n", 490 | " 0.052567025320850606\n", 491 | " 0.12661635054463663" 492 | ] 493 | }, 494 | "execution_count": 18, 495 | "metadata": {}, 496 | "output_type": "execute_result" 497 | } 498 | ], 499 | "source": [ 500 | "# apply the forward lineare map of operator A to domain vector m, returning range vector d\n", 501 | "d = A*m" 502 | ] 503 | }, 504 | { 505 | "cell_type": "code", 506 | "execution_count": 19, 507 | "metadata": {}, 508 | "outputs": [ 509 | { 510 | "data": { 511 | "text/plain": [ 512 | "2-element Array{Float64,1}:\n", 513 | " 0.052567025320850606\n", 514 | " 0.12661635054463663" 515 | ] 516 | }, 517 | "execution_count": 19, 518 | "metadata": {}, 519 | "output_type": "execute_result" 520 | } 521 | ], 522 | "source": [ 523 | "# inplace version that stores A*m in the supplied range vector d\n", 524 | "mul!(d,A,m)" 525 | ] 526 | }, 527 | { 528 | "cell_type": "code", 529 | "execution_count": 20, 530 | "metadata": {}, 531 | "outputs": [ 532 | { 533 | "data": { 534 | "text/plain": [ 535 | "2-element Array{Float64,1}:\n", 536 | " 0.015930932602953682\n", 537 | " 0.09594102182887355" 538 | ] 539 | }, 540 | "execution_count": 20, 541 | "metadata": {}, 542 | "output_type": "execute_result" 543 | } 544 | ], 545 | "source": [ 546 | "# apply the adjoint lineare map of operator A to range vector d, returning domain vector a\n", 547 | "a = A'*d" 548 | ] 549 | }, 550 | { 551 | "cell_type": "code", 552 | "execution_count": 21, 553 | "metadata": {}, 554 | "outputs": [ 555 | { 556 | "data": { 557 | "text/plain": [ 558 | "2-element Array{Float64,1}:\n", 559 | " 0.015930932602953682\n", 560 | " 0.09594102182887355" 561 | ] 562 | }, 563 | "execution_count": 21, 564 | "metadata": {}, 565 | "output_type": "execute_result" 566 | } 567 | ], 568 | "source": [ 569 | "# inplace version that stores A'*d in the supplied domain vector a\n", 570 | "mul!(a,A',d)" 571 | ] 572 | }, 573 | { 574 | "cell_type": "markdown", 575 | "metadata": {}, 576 | "source": [ 577 | "### Example 2: Nonlinear operator" 578 | ] 579 | }, 580 | { 581 | "cell_type": "code", 582 | "execution_count": 22, 583 | "metadata": {}, 584 | "outputs": [ 585 | { 586 | "data": { 587 | "text/plain": [ 588 | "\"Jet nonlinear operator, (64,) → (64,)\"" 589 | ] 590 | }, 591 | "execution_count": 22, 592 | "metadata": {}, 593 | "output_type": "execute_result" 594 | } 595 | ], 596 | "source": [ 597 | "F = JopEnvelope(JetSpace(Float64,64))" 598 | ] 599 | }, 600 | { 601 | "cell_type": "code", 602 | "execution_count": 23, 603 | "metadata": {}, 604 | "outputs": [ 605 | { 606 | "data": { 607 | "text/plain": [ 608 | "64-element Array{Float64,1}:\n", 609 | " 0.7873410404866608\n", 610 | " -0.5233121035144728\n", 611 | " 0.42728671747038627\n", 612 | " -0.002892130089680478\n", 613 | " -0.2398757138090306\n", 614 | " 0.23363758854948635\n", 615 | " -0.8632383410363862\n", 616 | " 0.8094999702558137\n", 617 | " 0.7373721196009533\n", 618 | " -0.08437230997083756\n", 619 | " 0.23061787544871004\n", 620 | " -0.2011114691746525\n", 621 | " -0.9073854820019345\n", 622 | " ⋮\n", 623 | " 0.8311901231230863\n", 624 | " 0.833835858592054\n", 625 | " -0.7647799131876134\n", 626 | " -0.8052944488782336\n", 627 | " -0.23982741422449383\n", 628 | " 0.1722639369637311\n", 629 | " 0.3952990191503347\n", 630 | " -0.29973959381730486\n", 631 | " -0.5928810620538112\n", 632 | " -0.43872461488334036\n", 633 | " -0.9079020953749457\n", 634 | " -0.5537077173372533" 635 | ] 636 | }, 637 | "execution_count": 23, 638 | "metadata": {}, 639 | "output_type": "execute_result" 640 | } 641 | ], 642 | "source": [ 643 | "# a random domain vector with values in [-1,+1]\n", 644 | "m = -1 .+ 2*rand(domain(F))" 645 | ] 646 | }, 647 | { 648 | "cell_type": "code", 649 | "execution_count": 24, 650 | "metadata": {}, 651 | "outputs": [ 652 | { 653 | "data": { 654 | "text/plain": [ 655 | "64-element Array{Float64,1}:\n", 656 | " 0.8152792466309035\n", 657 | " 0.5500801380446221\n", 658 | " 0.7771424010655119\n", 659 | " 0.6140706657193801\n", 660 | " 0.5860998905031608\n", 661 | " 0.46506913558398316\n", 662 | " 0.9998398568457513\n", 663 | " 1.248797504750526\n", 664 | " 0.8861613544244218\n", 665 | " 0.32971901290216943\n", 666 | " 0.24088562199134494\n", 667 | " 0.7553378746598928\n", 668 | " 1.0321226878354806\n", 669 | " ⋮\n", 670 | " 0.8420060215910247\n", 671 | " 1.6888733313347455\n", 672 | " 1.437383866992587\n", 673 | " 0.8129517027285474\n", 674 | " 0.31714407963954655\n", 675 | " 0.2012550827231281\n", 676 | " 0.6027408120301202\n", 677 | " 0.8501500537445098\n", 678 | " 0.6512171114226268\n", 679 | " 0.478704937372717\n", 680 | " 0.9125340046421397\n", 681 | " 1.2353920811348877" 682 | ] 683 | }, 684 | "execution_count": 24, 685 | "metadata": {}, 686 | "output_type": "execute_result" 687 | } 688 | ], 689 | "source": [ 690 | "# Apply the nonlinear envelope operator to the domain vector m and return the result in the range vector d\n", 691 | "d = F*m" 692 | ] 693 | }, 694 | { 695 | "cell_type": "code", 696 | "execution_count": 25, 697 | "metadata": {}, 698 | "outputs": [ 699 | { 700 | "data": { 701 | "image/png": "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", 702 | "text/plain": [ 703 | "Figure(PyObject
)" 704 | ] 705 | }, 706 | "metadata": {}, 707 | "output_type": "display_data" 708 | }, 709 | { 710 | "data": { 711 | "text/plain": [ 712 | "PyObject Text(0.5, 1.0, 'Envelope of signal m')" 713 | ] 714 | }, 715 | "execution_count": 25, 716 | "metadata": {}, 717 | "output_type": "execute_result" 718 | } 719 | ], 720 | "source": [ 721 | "figure(figsize=(10,5))\n", 722 | "plot(m, label=\"m\")\n", 723 | "plot(d, label=\"d\")\n", 724 | "legend()\n", 725 | "title(\"Envelope of signal m\")" 726 | ] 727 | }, 728 | { 729 | "cell_type": "code", 730 | "execution_count": 26, 731 | "metadata": {}, 732 | "outputs": [ 733 | { 734 | "data": { 735 | "text/plain": [ 736 | "\"Jet linear operator, (64,) → (64,)\"" 737 | ] 738 | }, 739 | "execution_count": 26, 740 | "metadata": {}, 741 | "output_type": "execute_result" 742 | } 743 | ], 744 | "source": [ 745 | "# compute the jacobian of F, copying the underlying jet\n", 746 | "J = jacobian(F, m) \n", 747 | "\n", 748 | "# compute the jacobian of F, sharing the underlying jet\n", 749 | "J = jacobian!(F, m)" 750 | ] 751 | }, 752 | { 753 | "cell_type": "markdown", 754 | "metadata": {}, 755 | "source": [ 756 | "## Jet compositions" 757 | ] 758 | }, 759 | { 760 | "cell_type": "markdown", 761 | "metadata": {}, 762 | "source": [ 763 | "To compose operators, we use the symbol: $\\circ$. This can be typed using unicode which is fully supported in Julia. In Jupyter (and most text editors with a Julia syntax plugin) you can use LaTeX syntax `\\circ` to produce $\\circ$." 764 | ] 765 | }, 766 | { 767 | "cell_type": "code", 768 | "execution_count": 27, 769 | "metadata": {}, 770 | "outputs": [ 771 | { 772 | "data": { 773 | "text/plain": [ 774 | "\"Jet linear operator, (2,) → (2,)\"" 775 | ] 776 | }, 777 | "execution_count": 27, 778 | "metadata": {}, 779 | "output_type": "execute_result" 780 | } 781 | ], 782 | "source": [ 783 | "A₁ = JopDiagonal(rand(2))\n", 784 | "A₂ = JopDiagonal(rand(2))\n", 785 | "A₃ = rand(2,2)\n", 786 | "\n", 787 | "A = A₃ ∘ A₂ ∘ A₁" 788 | ] 789 | }, 790 | { 791 | "cell_type": "code", 792 | "execution_count": 28, 793 | "metadata": {}, 794 | "outputs": [ 795 | { 796 | "data": { 797 | "text/plain": [ 798 | "true" 799 | ] 800 | }, 801 | "execution_count": 28, 802 | "metadata": {}, 803 | "output_type": "execute_result" 804 | } 805 | ], 806 | "source": [ 807 | "# test the composition behaves as expected\n", 808 | "m = rand(domain(A))\n", 809 | "A*m ≈ A₃ * (A₂ * (A₁ * m))" 810 | ] 811 | }, 812 | { 813 | "cell_type": "markdown", 814 | "metadata": {}, 815 | "source": [ 816 | "## Jet linear combinations\n", 817 | "Compositions of linear operators do not require the `\\circ` symbol" 818 | ] 819 | }, 820 | { 821 | "cell_type": "code", 822 | "execution_count": 29, 823 | "metadata": {}, 824 | "outputs": [ 825 | { 826 | "data": { 827 | "text/plain": [ 828 | "true" 829 | ] 830 | }, 831 | "execution_count": 29, 832 | "metadata": {}, 833 | "output_type": "execute_result" 834 | } 835 | ], 836 | "source": [ 837 | "A = 2.0*A₁ - 3.0*A₂ + 4.0*A₃\n", 838 | "A*m ≈ 2.0*(A₁*m) - 3.0*(A₂*m) + 4.0*(A₃*m)" 839 | ] 840 | }, 841 | { 842 | "cell_type": "markdown", 843 | "metadata": {}, 844 | "source": [ 845 | "## Jet nonlinear combinations\n", 846 | "You may compose arbitrary combinations of linear and nonlinear operators, provided domains and ranges match up" 847 | ] 848 | }, 849 | { 850 | "cell_type": "code", 851 | "execution_count": 30, 852 | "metadata": {}, 853 | "outputs": [ 854 | { 855 | "data": { 856 | "text/plain": [ 857 | "10-element Array{Float64,1}:\n", 858 | " 0.5918197463999675\n", 859 | " 0.6300353386716022\n", 860 | " 0.7431101721172502\n", 861 | " 0.573790745606475\n", 862 | " 0.49761696970045355\n", 863 | " 0.5837764051854917\n", 864 | " 0.3825621497045931\n", 865 | " 0.647420541021042\n", 866 | " 0.8163532424142848\n", 867 | " 0.3562883687113704" 868 | ] 869 | }, 870 | "execution_count": 30, 871 | "metadata": {}, 872 | "output_type": "execute_result" 873 | } 874 | ], 875 | "source": [ 876 | "A₁ = JopDiagonal(rand(Float64,10))\n", 877 | "A₂ = JopDiagonal(rand(Float64,10))\n", 878 | "E = JopEnvelope(JetSpace(Float64,10))\n", 879 | "\n", 880 | "op = 2.0*A₁∘E∘A₂\n", 881 | "m = rand(domain(op))\n", 882 | "d = op*m" 883 | ] 884 | }, 885 | { 886 | "cell_type": "markdown", 887 | "metadata": {}, 888 | "source": [ 889 | "# Jet block operators\n", 890 | "We use block operators extensively, particular in the context of full waveform inversion where each source is assigned to a block. " 891 | ] 892 | }, 893 | { 894 | "cell_type": "code", 895 | "execution_count": 31, 896 | "metadata": {}, 897 | "outputs": [ 898 | { 899 | "data": { 900 | "text/plain": [ 901 | "\"Jet linear operator, (4,) → (2,)\"" 902 | ] 903 | }, 904 | "execution_count": 31, 905 | "metadata": {}, 906 | "output_type": "execute_result" 907 | } 908 | ], 909 | "source": [ 910 | "A = @blockop [JopDiagonal(rand(2)) JopDiagonal(rand(2))]" 911 | ] 912 | }, 913 | { 914 | "cell_type": "code", 915 | "execution_count": 32, 916 | "metadata": {}, 917 | "outputs": [ 918 | { 919 | "data": { 920 | "text/plain": [ 921 | "4-element Jets.BlockArray{Float64,Array{Float64,1}}:\n", 922 | " 0.6639966547572143\n", 923 | " 0.010908114476342323\n", 924 | " 0.3448530800797167\n", 925 | " 0.2882051298870547" 926 | ] 927 | }, 928 | "execution_count": 32, 929 | "metadata": {}, 930 | "output_type": "execute_result" 931 | } 932 | ], 933 | "source": [ 934 | "m = rand(domain(A))" 935 | ] 936 | }, 937 | { 938 | "cell_type": "code", 939 | "execution_count": 33, 940 | "metadata": {}, 941 | "outputs": [ 942 | { 943 | "data": { 944 | "text/plain": [ 945 | "2-element Jets.BlockArray{Float64,Array{Float64,1}}:\n", 946 | " 0.3922648043710911\n", 947 | " 0.09965694281292975" 948 | ] 949 | }, 950 | "execution_count": 33, 951 | "metadata": {}, 952 | "output_type": "execute_result" 953 | } 954 | ], 955 | "source": [ 956 | "d = A*m" 957 | ] 958 | }, 959 | { 960 | "cell_type": "markdown", 961 | "metadata": {}, 962 | "source": [ 963 | "We use array comprehensions extensively in connection with the block operator" 964 | ] 965 | }, 966 | { 967 | "cell_type": "code", 968 | "execution_count": 34, 969 | "metadata": {}, 970 | "outputs": [ 971 | { 972 | "data": { 973 | "text/plain": [ 974 | "\"Jet linear operator, (6,) → (4,)\"" 975 | ] 976 | }, 977 | "execution_count": 34, 978 | "metadata": {}, 979 | "output_type": "execute_result" 980 | } 981 | ], 982 | "source": [ 983 | "A = @blockop [JopDiagonal(rand(2)) for irow=1:2, icol=1:3]" 984 | ] 985 | }, 986 | { 987 | "cell_type": "code", 988 | "execution_count": 35, 989 | "metadata": {}, 990 | "outputs": [ 991 | { 992 | "data": { 993 | "text/plain": [ 994 | "(2, 3)" 995 | ] 996 | }, 997 | "execution_count": 35, 998 | "metadata": {}, 999 | "output_type": "execute_result" 1000 | } 1001 | ], 1002 | "source": [ 1003 | "nblocks(A)" 1004 | ] 1005 | }, 1006 | { 1007 | "cell_type": "code", 1008 | "execution_count": 36, 1009 | "metadata": {}, 1010 | "outputs": [ 1011 | { 1012 | "data": { 1013 | "text/plain": [ 1014 | "2" 1015 | ] 1016 | }, 1017 | "execution_count": 36, 1018 | "metadata": {}, 1019 | "output_type": "execute_result" 1020 | } 1021 | ], 1022 | "source": [ 1023 | "nblocks(A,1)" 1024 | ] 1025 | }, 1026 | { 1027 | "cell_type": "code", 1028 | "execution_count": 37, 1029 | "metadata": {}, 1030 | "outputs": [ 1031 | { 1032 | "data": { 1033 | "text/plain": [ 1034 | "3" 1035 | ] 1036 | }, 1037 | "execution_count": 37, 1038 | "metadata": {}, 1039 | "output_type": "execute_result" 1040 | } 1041 | ], 1042 | "source": [ 1043 | "nblocks(A,2)" 1044 | ] 1045 | }, 1046 | { 1047 | "cell_type": "code", 1048 | "execution_count": 38, 1049 | "metadata": {}, 1050 | "outputs": [ 1051 | { 1052 | "data": { 1053 | "text/plain": [ 1054 | "\"Jet linear operator, (2,) → (2,)\"" 1055 | ] 1056 | }, 1057 | "execution_count": 38, 1058 | "metadata": {}, 1059 | "output_type": "execute_result" 1060 | } 1061 | ], 1062 | "source": [ 1063 | "getblock(A,1,1)" 1064 | ] 1065 | }, 1066 | { 1067 | "cell_type": "code", 1068 | "execution_count": null, 1069 | "metadata": {}, 1070 | "outputs": [], 1071 | "source": [] 1072 | } 1073 | ], 1074 | "metadata": { 1075 | "kernelspec": { 1076 | "display_name": "Julia 1.5.2", 1077 | "language": "julia", 1078 | "name": "julia-1.5" 1079 | }, 1080 | "language_info": { 1081 | "file_extension": ".jl", 1082 | "mimetype": "application/julia", 1083 | "name": "julia", 1084 | "version": "1.5.2" 1085 | } 1086 | }, 1087 | "nbformat": 4, 1088 | "nbformat_minor": 4 1089 | } 1090 | -------------------------------------------------------------------------------- /10_jets_basics/02-distributedjets-basics.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# DistributedJets.jl\n", 8 | "Package that extends Jets to work with parallel distributed block operators. This gives us a consistent way to book-keep distributed memory and computation. It relies heavily on the community (public) DistributedArrays.jl package." 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "metadata": {}, 14 | "source": [ 15 | "## Add 4 workers" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": 1, 21 | "metadata": {}, 22 | "outputs": [ 23 | { 24 | "data": { 25 | "text/plain": [ 26 | "4-element Array{Int64,1}:\n", 27 | " 2\n", 28 | " 3\n", 29 | " 4\n", 30 | " 5" 31 | ] 32 | }, 33 | "execution_count": 1, 34 | "metadata": {}, 35 | "output_type": "execute_result" 36 | } 37 | ], 38 | "source": [ 39 | "using Distributed\n", 40 | "addprocs(4)" 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": {}, 46 | "source": [ 47 | "## Add the packages we need on the workers\n", 48 | "We add the packages we need on the workers, accomplished with the `@everywhere` macro" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 2, 54 | "metadata": {}, 55 | "outputs": [], 56 | "source": [ 57 | "@everywhere using DistributedArrays, DistributedJets, Jets, JetPack" 58 | ] 59 | }, 60 | { 61 | "cell_type": "markdown", 62 | "metadata": {}, 63 | "source": [ 64 | "## Example\n", 65 | "We use the same blockop macro as is used in `Jets`, but now supply a distributed array `DArray`, with some additional information about how the work is distributed. \n", 66 | "\n", 67 | "**See also** the help docs:\n", 68 | "```julia\n", 69 | "?DArray\n", 70 | "?@blockop\n", 71 | "```" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": 3, 77 | "metadata": {}, 78 | "outputs": [ 79 | { 80 | "data": { 81 | "text/plain": [ 82 | "\"Jet linear operator, (8,) → (8,)\"" 83 | ] 84 | }, 85 | "execution_count": 3, 86 | "metadata": {}, 87 | "output_type": "execute_result" 88 | } 89 | ], 90 | "source": [ 91 | "A = @blockop DArray(I->[JopDiagonal(rand(2)) for irow in I[1], icol in I[2]], (4,4), workers(), [2,2])" 92 | ] 93 | }, 94 | { 95 | "cell_type": "markdown", 96 | "metadata": {}, 97 | "source": [ 98 | "#### Explanation for arguments to `DArray` used above:\n", 99 | "* `[JopDiagonal(rand(2)) for irow in I[1], icol in I[2]]` is the *constructor* for each of the blocks in the distributed block operator. This runs *remotely* on the workers as specified below.\n", 100 | "* `(4,4)` is the overall size of the block operator: 4 rows and 4 columns for a total of 16 elements\n", 101 | "* `workers()` supplies the process identifiers (pids) of the workers the operators will be constructed on: our 4 workers with pids `2,3,4,5`\n", 102 | "* `[2,2]` describes how the block operator array should be distributed in each dimension: each worker gets 2 rows and 2 columns." 103 | ] 104 | }, 105 | { 106 | "cell_type": "markdown", 107 | "metadata": {}, 108 | "source": [ 109 | "#### Matrix representation of the block operator\n", 110 | "\n", 111 | "We show the pids for the workers as assigned to the 4x4 block operator. Recall that each *cell* of the block operator is a `JotOperator`.\n", 112 | "\n", 113 | "$$\n", 114 | "\\begin{bmatrix}\n", 115 | " 2 & 2 & 3 & 3 \\\\\n", 116 | " 2 & 2 & 3 & 3 \\\\\n", 117 | " 4 & 4 & 5 & 5 \\\\\n", 118 | " 4 & 4 & 5 & 5\n", 119 | "\\end{bmatrix}\n", 120 | "$$" 121 | ] 122 | }, 123 | { 124 | "cell_type": "markdown", 125 | "metadata": {}, 126 | "source": [ 127 | "#### Getting information about block operator layouts\n", 128 | "We can use various methods to understand which processes store which blocks\n", 129 | "\n", 130 | "* `procs(A)` Shows how workers are distributed in the block operator. Note this is the layout as described by the last argument to `@blockop` above: `[2,2]`. \n", 131 | "\n", 132 | "* `blockmap(A)` Shows what elements of the overall block operator are assigned to each worker. This information is also shown in the matrix representation above.\n", 133 | " * pid 2 has row-blocks 1:2, and column blocks 1:2\n", 134 | " * pid 4 has row-blocks 1:2, and column blocks 3:4\n", 135 | " * pid 5 has row-blocks 3:4, and column blocks 1:2\n", 136 | " * pid 6 has row-blocks 3:4, and column blocks 3:4\n", 137 | "\n", 138 | "\n", 139 | "* `remotecall_fetch(localblockindices, i, A)` will return the part of the `blockmap` operator assigned to pid `i`.\n", 140 | "\n", 141 | "We exercise these methods in the next four cells below." 142 | ] 143 | }, 144 | { 145 | "cell_type": "code", 146 | "execution_count": 4, 147 | "metadata": {}, 148 | "outputs": [ 149 | { 150 | "data": { 151 | "text/plain": [ 152 | "2×2 Array{Int64,2}:\n", 153 | " 2 4\n", 154 | " 3 5" 155 | ] 156 | }, 157 | "execution_count": 4, 158 | "metadata": {}, 159 | "output_type": "execute_result" 160 | } 161 | ], 162 | "source": [ 163 | "procs(A)" 164 | ] 165 | }, 166 | { 167 | "cell_type": "code", 168 | "execution_count": 5, 169 | "metadata": {}, 170 | "outputs": [ 171 | { 172 | "data": { 173 | "text/plain": [ 174 | "2×2 Array{Tuple{UnitRange{Int64},UnitRange{Int64}},2}:\n", 175 | " (1:2, 1:2) (1:2, 3:4)\n", 176 | " (3:4, 1:2) (3:4, 3:4)" 177 | ] 178 | }, 179 | "execution_count": 5, 180 | "metadata": {}, 181 | "output_type": "execute_result" 182 | } 183 | ], 184 | "source": [ 185 | "blockmap(A)" 186 | ] 187 | }, 188 | { 189 | "cell_type": "code", 190 | "execution_count": 6, 191 | "metadata": {}, 192 | "outputs": [ 193 | { 194 | "data": { 195 | "text/plain": [ 196 | "(1:2, 1:2)" 197 | ] 198 | }, 199 | "execution_count": 6, 200 | "metadata": {}, 201 | "output_type": "execute_result" 202 | } 203 | ], 204 | "source": [ 205 | "remotecall_fetch(localblockindices, 2, A)" 206 | ] 207 | }, 208 | { 209 | "cell_type": "code", 210 | "execution_count": 7, 211 | "metadata": {}, 212 | "outputs": [ 213 | { 214 | "data": { 215 | "text/plain": [ 216 | "(3:4, 1:2)" 217 | ] 218 | }, 219 | "execution_count": 7, 220 | "metadata": {}, 221 | "output_type": "execute_result" 222 | } 223 | ], 224 | "source": [ 225 | "remotecall_fetch(localblockindices, 3, A)" 226 | ] 227 | }, 228 | { 229 | "cell_type": "markdown", 230 | "metadata": {}, 231 | "source": [ 232 | "## Obtaining blocks from a distributed block operator\n", 233 | "You can obtain the blocks of the operator in two ways. \n", 234 | "* `getblock(A,1,1)` fetches block 1,1, and passes a copy of it from pid 2 to the master.\n", 235 | "\n", 236 | "* `remotecall(getblock, 2, A, 1, 1)` get a `Future` for block 1,1 from pid 2. No copy is made." 237 | ] 238 | }, 239 | { 240 | "cell_type": "code", 241 | "execution_count": 8, 242 | "metadata": {}, 243 | "outputs": [ 244 | { 245 | "data": { 246 | "text/plain": [ 247 | "\"Jet linear operator, (2,) → (2,)\"" 248 | ] 249 | }, 250 | "execution_count": 8, 251 | "metadata": {}, 252 | "output_type": "execute_result" 253 | } 254 | ], 255 | "source": [ 256 | "getblock(A,1,1)" 257 | ] 258 | }, 259 | { 260 | "cell_type": "code", 261 | "execution_count": 9, 262 | "metadata": {}, 263 | "outputs": [ 264 | { 265 | "data": { 266 | "text/plain": [ 267 | "Future(2, 1, 61, nothing)" 268 | ] 269 | }, 270 | "execution_count": 9, 271 | "metadata": {}, 272 | "output_type": "execute_result" 273 | } 274 | ], 275 | "source": [ 276 | "remotecall(getblock, 2, A, 1, 1)" 277 | ] 278 | }, 279 | { 280 | "cell_type": "markdown", 281 | "metadata": {}, 282 | "source": [ 283 | "## Distributed block arrays (DBArray)\n", 284 | "`DBArray` is used with distributed block operators, and handles the bookeeping and storage of arrays on workers associated with the distributed operators.\n", 285 | "\n", 286 | "We show examples below for creating `DBArray` for domain and range, and getting and setting blocks." 287 | ] 288 | }, 289 | { 290 | "cell_type": "code", 291 | "execution_count": 10, 292 | "metadata": {}, 293 | "outputs": [ 294 | { 295 | "data": { 296 | "text/plain": [ 297 | "8-element DBArray{Float64,Jets.BlockArray{Float64,Array{Float64,1}},Array{Jets.BlockArray{Float64,Array{Float64,1}},1}}:\n", 298 | " 0.03492578552266079\n", 299 | " 0.7928324970256673\n", 300 | " 0.4798569433525588\n", 301 | " 0.3212078230909068\n", 302 | " 0.9428391021870626\n", 303 | " 0.1736302165843273\n", 304 | " 0.42915578969841484\n", 305 | " 0.4696486029593059" 306 | ] 307 | }, 308 | "execution_count": 10, 309 | "metadata": {}, 310 | "output_type": "execute_result" 311 | } 312 | ], 313 | "source": [ 314 | "d = rand(range(A))" 315 | ] 316 | }, 317 | { 318 | "cell_type": "code", 319 | "execution_count": 11, 320 | "metadata": {}, 321 | "outputs": [ 322 | { 323 | "data": { 324 | "text/plain": [ 325 | "2-element Array{Int64,1}:\n", 326 | " 2\n", 327 | " 3" 328 | ] 329 | }, 330 | "execution_count": 11, 331 | "metadata": {}, 332 | "output_type": "execute_result" 333 | } 334 | ], 335 | "source": [ 336 | "procs(d)" 337 | ] 338 | }, 339 | { 340 | "cell_type": "code", 341 | "execution_count": 12, 342 | "metadata": {}, 343 | "outputs": [ 344 | { 345 | "data": { 346 | "text/plain": [ 347 | "2-element Array{UnitRange{Int64},1}:\n", 348 | " 1:2\n", 349 | " 3:4" 350 | ] 351 | }, 352 | "execution_count": 12, 353 | "metadata": {}, 354 | "output_type": "execute_result" 355 | } 356 | ], 357 | "source": [ 358 | "blockmap(d)" 359 | ] 360 | }, 361 | { 362 | "cell_type": "code", 363 | "execution_count": 13, 364 | "metadata": {}, 365 | "outputs": [ 366 | { 367 | "data": { 368 | "text/plain": [ 369 | "8-element DBArray{Float64,Jets.BlockArray{Float64,Array{Float64,1}},Array{Jets.BlockArray{Float64,Array{Float64,1}},1}}:\n", 370 | " 0.5380589955358761\n", 371 | " 0.5039985475004294\n", 372 | " 0.4223251101218566\n", 373 | " 0.5091316025637858\n", 374 | " 0.15948303803609343\n", 375 | " 0.7798568700302135\n", 376 | " 0.8402234222183054\n", 377 | " 0.0568762097885378" 378 | ] 379 | }, 380 | "execution_count": 13, 381 | "metadata": {}, 382 | "output_type": "execute_result" 383 | } 384 | ], 385 | "source": [ 386 | "m = rand(domain(A))" 387 | ] 388 | }, 389 | { 390 | "cell_type": "code", 391 | "execution_count": 14, 392 | "metadata": {}, 393 | "outputs": [ 394 | { 395 | "data": { 396 | "text/plain": [ 397 | "2-element Array{Int64,1}:\n", 398 | " 2\n", 399 | " 4" 400 | ] 401 | }, 402 | "execution_count": 14, 403 | "metadata": {}, 404 | "output_type": "execute_result" 405 | } 406 | ], 407 | "source": [ 408 | "procs(m)" 409 | ] 410 | }, 411 | { 412 | "cell_type": "code", 413 | "execution_count": 15, 414 | "metadata": {}, 415 | "outputs": [ 416 | { 417 | "data": { 418 | "text/plain": [ 419 | "2-element Array{UnitRange{Int64},1}:\n", 420 | " 1:2\n", 421 | " 3:4" 422 | ] 423 | }, 424 | "execution_count": 15, 425 | "metadata": {}, 426 | "output_type": "execute_result" 427 | } 428 | ], 429 | "source": [ 430 | "blockmap(m)" 431 | ] 432 | }, 433 | { 434 | "cell_type": "code", 435 | "execution_count": 16, 436 | "metadata": {}, 437 | "outputs": [ 438 | { 439 | "data": { 440 | "text/plain": [ 441 | "2-element Array{Float64,1}:\n", 442 | " 0.03492578552266079\n", 443 | " 0.7928324970256673" 444 | ] 445 | }, 446 | "execution_count": 16, 447 | "metadata": {}, 448 | "output_type": "execute_result" 449 | } 450 | ], 451 | "source": [ 452 | "# fetch block 1, and passes a copy of it from pid 2 to the master\n", 453 | "getblock(d, 1)" 454 | ] 455 | }, 456 | { 457 | "cell_type": "code", 458 | "execution_count": 17, 459 | "metadata": {}, 460 | "outputs": [ 461 | { 462 | "data": { 463 | "text/plain": [ 464 | "8-element DBArray{Float64,Jets.BlockArray{Float64,Array{Float64,1}},Array{Jets.BlockArray{Float64,Array{Float64,1}},1}}:\n", 465 | " 1.0\n", 466 | " 1.0\n", 467 | " 0.4798569433525588\n", 468 | " 0.3212078230909068\n", 469 | " 0.9428391021870626\n", 470 | " 0.1736302165843273\n", 471 | " 0.42915578969841484\n", 472 | " 0.4696486029593059" 473 | ] 474 | }, 475 | "execution_count": 17, 476 | "metadata": {}, 477 | "output_type": "execute_result" 478 | } 479 | ], 480 | "source": [ 481 | "# passes a new array from the master to pid 2, and assigns it to block 1\n", 482 | "setblock!(d, 1, ones(2))\n", 483 | "d" 484 | ] 485 | }, 486 | { 487 | "cell_type": "code", 488 | "execution_count": 18, 489 | "metadata": {}, 490 | "outputs": [ 491 | { 492 | "data": { 493 | "text/plain": [ 494 | "2-element Array{Float64,1}:\n", 495 | " 1.0\n", 496 | " 1.0" 497 | ] 498 | }, 499 | "execution_count": 18, 500 | "metadata": {}, 501 | "output_type": "execute_result" 502 | } 503 | ], 504 | "source": [ 505 | "# on pid=2 we get a reference to the block\n", 506 | "remotecall_fetch(getblock, 2, d, 1) " 507 | ] 508 | }, 509 | { 510 | "cell_type": "code", 511 | "execution_count": 19, 512 | "metadata": {}, 513 | "outputs": [ 514 | { 515 | "data": { 516 | "text/plain": [ 517 | "8-element DBArray{Float64,Jets.BlockArray{Float64,Array{Float64,1}},Array{Jets.BlockArray{Float64,Array{Float64,1}},1}}:\n", 518 | " 2.0\n", 519 | " 2.0\n", 520 | " 0.4798569433525588\n", 521 | " 0.3212078230909068\n", 522 | " 0.9428391021870626\n", 523 | " 0.1736302165843273\n", 524 | " 0.42915578969841484\n", 525 | " 0.4696486029593059" 526 | ] 527 | }, 528 | "execution_count": 19, 529 | "metadata": {}, 530 | "output_type": "execute_result" 531 | } 532 | ], 533 | "source": [ 534 | "@everywhere function remotegetblock_mutating(d, i)\n", 535 | " dᵢ = getblock(d, i)\n", 536 | " dᵢ .= 2.0\n", 537 | " nothing\n", 538 | "end\n", 539 | "remotecall_fetch(remotegetblock_mutating, 2, d, 1)\n", 540 | "d" 541 | ] 542 | }, 543 | { 544 | "cell_type": "markdown", 545 | "metadata": {}, 546 | "source": [ 547 | "# Specialized distributed block operators\n", 548 | "\n", 549 | "## tall-and-skinny\n", 550 | "Block operators with a single column-block. This specialization is often used in FWI. The model is stored on the master." 551 | ] 552 | }, 553 | { 554 | "cell_type": "code", 555 | "execution_count": 20, 556 | "metadata": {}, 557 | "outputs": [ 558 | { 559 | "data": { 560 | "text/plain": [ 561 | "\"Jet linear operator, (2,) → (8,)\"" 562 | ] 563 | }, 564 | "execution_count": 20, 565 | "metadata": {}, 566 | "output_type": "execute_result" 567 | } 568 | ], 569 | "source": [ 570 | "A = @blockop DArray(I->[JopDiagonal(rand(2)) for irow=1:4, icol=1:1], (4,1))" 571 | ] 572 | }, 573 | { 574 | "cell_type": "code", 575 | "execution_count": 21, 576 | "metadata": {}, 577 | "outputs": [ 578 | { 579 | "data": { 580 | "text/plain": [ 581 | "4×1 Array{Tuple{UnitRange{Int64},UnitRange{Int64}},2}:\n", 582 | " (1:1, 1:1)\n", 583 | " (2:2, 1:1)\n", 584 | " (3:3, 1:1)\n", 585 | " (4:4, 1:1)" 586 | ] 587 | }, 588 | "execution_count": 21, 589 | "metadata": {}, 590 | "output_type": "execute_result" 591 | } 592 | ], 593 | "source": [ 594 | "blockmap(A)" 595 | ] 596 | }, 597 | { 598 | "cell_type": "code", 599 | "execution_count": 22, 600 | "metadata": {}, 601 | "outputs": [ 602 | { 603 | "data": { 604 | "text/plain": [ 605 | "4-element Array{UnitRange{Int64},1}:\n", 606 | " 1:1\n", 607 | " 2:2\n", 608 | " 3:3\n", 609 | " 4:4" 610 | ] 611 | }, 612 | "execution_count": 22, 613 | "metadata": {}, 614 | "output_type": "execute_result" 615 | } 616 | ], 617 | "source": [ 618 | "d = rand(range(A))\n", 619 | "blockmap(d)" 620 | ] 621 | }, 622 | { 623 | "cell_type": "code", 624 | "execution_count": 23, 625 | "metadata": {}, 626 | "outputs": [ 627 | { 628 | "data": { 629 | "text/plain": [ 630 | "2-element Array{Float64,1}:\n", 631 | " 0.2850422159251276\n", 632 | " 0.2507849203072321" 633 | ] 634 | }, 635 | "execution_count": 23, 636 | "metadata": {}, 637 | "output_type": "execute_result" 638 | } 639 | ], 640 | "source": [ 641 | "m = rand(domain(A))" 642 | ] 643 | }, 644 | { 645 | "cell_type": "markdown", 646 | "metadata": {}, 647 | "source": [ 648 | "## Sparse block diagonal\n", 649 | "This is the only sparse block operator that we support. Supporting a larger variety of sparse layouts is possible, but would require an engineering effort to build a proper sparse distributed arrays package.\n", 650 | "\n", 651 | "Below we build a sparse block diagonal with 4 rows and 4 columns, with operators along the diagonal. We use `JopZeroBlock` to specify that the off diagonals do not have operators. The distribution of pids is shown in the matrix below. \n", 652 | "\n", 653 | "$$\n", 654 | "\\begin{bmatrix}\n", 655 | " 2 & 0 & 0 & 0 \\\\\n", 656 | " 0 & 3 & 0 & 0 \\\\\n", 657 | " 0 & 0 & 4 & 0 \\\\\n", 658 | " 0 & 0 & 0 & 5\n", 659 | "\\end{bmatrix}\n", 660 | "$$" 661 | ] 662 | }, 663 | { 664 | "cell_type": "code", 665 | "execution_count": 24, 666 | "metadata": {}, 667 | "outputs": [ 668 | { 669 | "data": { 670 | "text/plain": [ 671 | "\"Jet linear operator, (8,) → (8,)\"" 672 | ] 673 | }, 674 | "execution_count": 24, 675 | "metadata": {}, 676 | "output_type": "execute_result" 677 | } 678 | ], 679 | "source": [ 680 | "A = @blockop DArray(\n", 681 | " I->[irow==icol ? JopDiagonal(rand(2)) : JopZeroBlock(JetSpace(Float64,2),JetSpace(Float64,2)) for irow in I[1], icol in I[2]],\n", 682 | " (4,4),\n", 683 | " workers()[1:4],\n", 684 | " [4,1]) isdiag=true" 685 | ] 686 | }, 687 | { 688 | "cell_type": "code", 689 | "execution_count": 25, 690 | "metadata": {}, 691 | "outputs": [ 692 | { 693 | "data": { 694 | "text/plain": [ 695 | "4×1 Array{Int64,2}:\n", 696 | " 2\n", 697 | " 3\n", 698 | " 4\n", 699 | " 5" 700 | ] 701 | }, 702 | "execution_count": 25, 703 | "metadata": {}, 704 | "output_type": "execute_result" 705 | } 706 | ], 707 | "source": [ 708 | "procs(A)" 709 | ] 710 | }, 711 | { 712 | "cell_type": "code", 713 | "execution_count": 26, 714 | "metadata": {}, 715 | "outputs": [ 716 | { 717 | "data": { 718 | "text/plain": [ 719 | "4×1 Array{Tuple{UnitRange{Int64},UnitRange{Int64}},2}:\n", 720 | " (1:1, 1:4)\n", 721 | " (2:2, 1:4)\n", 722 | " (3:3, 1:4)\n", 723 | " (4:4, 1:4)" 724 | ] 725 | }, 726 | "execution_count": 26, 727 | "metadata": {}, 728 | "output_type": "execute_result" 729 | } 730 | ], 731 | "source": [ 732 | "blockmap(A)" 733 | ] 734 | }, 735 | { 736 | "cell_type": "code", 737 | "execution_count": 27, 738 | "metadata": {}, 739 | "outputs": [ 740 | { 741 | "data": { 742 | "text/plain": [ 743 | "4-element Array{UnitRange{Int64},1}:\n", 744 | " 1:1\n", 745 | " 2:2\n", 746 | " 3:3\n", 747 | " 4:4" 748 | ] 749 | }, 750 | "execution_count": 27, 751 | "metadata": {}, 752 | "output_type": "execute_result" 753 | } 754 | ], 755 | "source": [ 756 | "d = rand(range(A))\n", 757 | "blockmap(d)" 758 | ] 759 | }, 760 | { 761 | "cell_type": "code", 762 | "execution_count": 28, 763 | "metadata": {}, 764 | "outputs": [ 765 | { 766 | "data": { 767 | "text/plain": [ 768 | "4-element Array{UnitRange{Int64},1}:\n", 769 | " 1:1\n", 770 | " 2:2\n", 771 | " 3:3\n", 772 | " 4:4" 773 | ] 774 | }, 775 | "execution_count": 28, 776 | "metadata": {}, 777 | "output_type": "execute_result" 778 | } 779 | ], 780 | "source": [ 781 | "m = rand(domain(A))\n", 782 | "blockmap(m)" 783 | ] 784 | }, 785 | { 786 | "cell_type": "code", 787 | "execution_count": null, 788 | "metadata": {}, 789 | "outputs": [], 790 | "source": [] 791 | } 792 | ], 793 | "metadata": { 794 | "kernelspec": { 795 | "display_name": "Julia 1.5.2", 796 | "language": "julia", 797 | "name": "julia-1.5" 798 | }, 799 | "language_info": { 800 | "file_extension": ".jl", 801 | "mimetype": "application/julia", 802 | "name": "julia", 803 | "version": "1.5.2" 804 | } 805 | }, 806 | "nbformat": 4, 807 | "nbformat_minor": 4 808 | } 809 | -------------------------------------------------------------------------------- /10_jets_basics/03-common_patterns.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Common usage patterns" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "## Create a block wavefield modeling operator from the geometry in a JavaSeis/CloudSeis file" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "```julia\n", 22 | "@everywhere using DistributedArrays, DistributedJets, Jets, JetPackWaveFD, TeaSeis, ParallelOperations\n", 23 | "\n", 24 | "function buildblock(ishot,ρ,io)\n", 25 | " h = readframehdrs(io,ishot)\n", 26 | " JopNlProp3DAcoIsoDenQ_DEO2_FDTD(\n", 27 | " sz = -get(prop(io,\"SOU_ELEV\"), h, 1),\n", 28 | " sy = get(prop(io,\"SOU_Y\"), h, 1),\n", 29 | " sx = get(prop(io,\"SOU_X\"), h, 1),\n", 30 | " rz = [-get(prop(io,\"REC_ELEV\"), h, i) for i = 1:fold(io,h)],\n", 31 | " ry = [get(prop(io,\"REC_Y\"), h, i) for i = 1:fold(io,h)],\n", 32 | " rx = [get(prop(io,\"REC_X\"), h, i) for i = 1:fold(io,h)],\n", 33 | " ntrec = size(io,1),\n", 34 | " dtrec = pincs(io,1),\n", 35 | " dtmod = 0.001,\n", 36 | " b = 1 ./ ρ,\n", 37 | " dz = 20.0,\n", 38 | " dy = 20.0,\n", 39 | " dx = 20.0)\n", 40 | "end\n", 41 | "\n", 42 | "function buildblocks(I,ρ_futures)\n", 43 | " io = jsopen(\"data.js\")\n", 44 | " ρ = localpart(ρ_futures)\n", 45 | " F = [buildblock(ishot,ρ,io) for ishot in I[1], j in 1:1]\n", 46 | " close(io)\n", 47 | " F\n", 48 | "end\n", 49 | "\n", 50 | "io = jsopen(\"data.js\")\n", 51 | "nshots = size(io,3) # assume one shot per frame\n", 52 | "close(io)\n", 53 | "\n", 54 | "nz,ny,nx=512,512,512\n", 55 | "ρ = 1.0*ones(nz,ny,nx)\n", 56 | "ρ_futures = bcast(ρ)\n", 57 | "\n", 58 | "F = @blockop DArray(I->buildblocks(I, ρ_futures), (nshots,1))\n", 59 | "```" 60 | ] 61 | }, 62 | { 63 | "cell_type": "markdown", 64 | "metadata": {}, 65 | "source": [ 66 | "## Populate a distributed block array from a JavaSeis/CloudSeis file" 67 | ] 68 | }, 69 | { 70 | "cell_type": "markdown", 71 | "metadata": {}, 72 | "source": [ 73 | "```julia\n", 74 | "@everywhere function readblocks!(d)\n", 75 | " io = jsopen(\"data.js\")\n", 76 | " for ishot in localblockindices(d)\n", 77 | " setblock!(d, ishot, readframetrcs(io, ishot))\n", 78 | " end\n", 79 | " close(io)\n", 80 | "end\n", 81 | "\n", 82 | "d = zeros(range(F))\n", 83 | "@sync for pid in procs(d)\n", 84 | " @async remotecall_fetch(readblocks!, pid, d)\n", 85 | "end\n", 86 | "```" 87 | ] 88 | }, 89 | { 90 | "cell_type": "markdown", 91 | "metadata": {}, 92 | "source": [ 93 | "## Computing cost over a set of shots from a distributed block array" 94 | ] 95 | }, 96 | { 97 | "cell_type": "markdown", 98 | "metadata": {}, 99 | "source": [ 100 | "```julia\n", 101 | "@everywhere function costperpid(dmod, dobs)\n", 102 | " phi = 0.0\n", 103 | " for iblock in localblockindices(fmod)\n", 104 | " phi += getblock(dobs,iblock) .- getblock(dmod,iblock)\n", 105 | " end\n", 106 | " phi\n", 107 | "end\n", 108 | "\n", 109 | "function cost(m, F, dobs)\n", 110 | " dmod = F*m #F is a block operators\n", 111 | " phi = zeros(nprocs(F))\n", 112 | " @sync for (ipid,pid) in enumerate(procs(F))\n", 113 | " @async begin\n", 114 | " phi[ipid] = remotecall_fetch(costperpid, pid, dmod, dobs)\n", 115 | " end\n", 116 | " end\n", 117 | " sum(phi)\n", 118 | "end\n", 119 | "\n", 120 | "phi = cost(m,F,dobs)\n", 121 | "```\n", 122 | "Note that the above can be done in a single line, but the pattern is useful for more interesting cost functions such as optimal transport. For the above L2 case, the single line would be:\n", 123 | "```julia\n", 124 | "phi = 0.5*norm(F*m .- d).^2\n", 125 | "```" 126 | ] 127 | }, 128 | { 129 | "cell_type": "code", 130 | "execution_count": null, 131 | "metadata": {}, 132 | "outputs": [], 133 | "source": [] 134 | } 135 | ], 136 | "metadata": { 137 | "kernelspec": { 138 | "display_name": "Julia 1.5.2", 139 | "language": "julia", 140 | "name": "julia-1.5" 141 | }, 142 | "language_info": { 143 | "file_extension": ".jl", 144 | "mimetype": "application/julia", 145 | "name": "julia", 146 | "version": "1.5.2" 147 | } 148 | }, 149 | "nbformat": 4, 150 | "nbformat_minor": 4 151 | } 152 | -------------------------------------------------------------------------------- /30_forward_modeling/05_DynamicParallel.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Distributed modeling with dynamic schedule\n", 8 | "We demonstrate dynamic scheduling using 2 workers to model 8 shots across Marmousi.\n", 9 | "\n", 10 | "Even though this is a 2D example, the model passed to the nonlinear operator below is 3D, with size [nz,nx,1] for the velocity only. In the case of variable density acoustics, the model would be of size [nz,nx,2]. " 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 1, 16 | "metadata": {}, 17 | "outputs": [], 18 | "source": [ 19 | "using Distributed" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 2, 25 | "metadata": {}, 26 | "outputs": [ 27 | { 28 | "data": { 29 | "text/plain": [ 30 | "2-element Array{Int64,1}:\n", 31 | " 2\n", 32 | " 3" 33 | ] 34 | }, 35 | "execution_count": 2, 36 | "metadata": {}, 37 | "output_type": "execute_result" 38 | } 39 | ], 40 | "source": [ 41 | "addprocs(2)" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": 3, 47 | "metadata": { 48 | "tags": [] 49 | }, 50 | "outputs": [], 51 | "source": [ 52 | "@everywhere using DistributedArrays, DistributedJets, Jets, WaveFD, JetPackWaveFD, DistributedOperations, Schedulers, Random" 53 | ] 54 | }, 55 | { 56 | "cell_type": "markdown", 57 | "metadata": {}, 58 | "source": [ 59 | "## Define the model \n", 60 | "Even though this is a 2D example, the model passed to the nonlinear operator below is 3D, with size [nz,nx,1] for the velocity only case. In the case of variable density acoustics, the model would be of size [nz,nx,2]. " 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": 4, 66 | "metadata": { 67 | "tags": [] 68 | }, 69 | "outputs": [ 70 | { 71 | "name": "stdout", 72 | "output_type": "stream", 73 | "text": [ 74 | "(dz, dx) = (20.0, 20.0)\n", 75 | "size(v) = (176, 851)\n", 76 | "size(m) = (176, 851, 1)\n" 77 | ] 78 | } 79 | ], 80 | "source": [ 81 | "v = read!(\"../20_marmousi_model_setup/marmousi_vp_20m_176x851.bin\", Array{Float32}(undef,176,851));\n", 82 | "dz,dx = 20.0,20.0\n", 83 | "nz,nx = size(v)\n", 84 | "m = reshape(v, (nz,nx,1))\n", 85 | "@show dz,dx\n", 86 | "@show size(v)\n", 87 | "@show size(m);" 88 | ] 89 | }, 90 | { 91 | "cell_type": "code", 92 | "execution_count": 5, 93 | "metadata": { 94 | "tags": [] 95 | }, 96 | "outputs": [ 97 | { 98 | "name": "stdout", 99 | "output_type": "stream", 100 | "text": [ 101 | "nshots = 8\n" 102 | ] 103 | } 104 | ], 105 | "source": [ 106 | "sx = range(0,length=8,stop=(851-1)*20)\n", 107 | "nshots = length(sx)\n", 108 | "@show nshots;" 109 | ] 110 | }, 111 | { 112 | "cell_type": "markdown", 113 | "metadata": {}, 114 | "source": [ 115 | "## Broadcast the model (m) to workers" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": 6, 121 | "metadata": {}, 122 | "outputs": [ 123 | { 124 | "data": { 125 | "text/plain": [ 126 | "ArrayFutures with pids=[2, 3, 1] and type (176, 851, 1)" 127 | ] 128 | }, 129 | "execution_count": 6, 130 | "metadata": {}, 131 | "output_type": "execute_result" 132 | } 133 | ], 134 | "source": [ 135 | "_m = bcast(m)" 136 | ] 137 | }, 138 | { 139 | "cell_type": "markdown", 140 | "metadata": {}, 141 | "source": [ 142 | "## Build a list of keyword arguments to be passed to the modeling operator\n", 143 | "Note that we have two workers on the same physical node, so we use half the number of threads on each." 144 | ] 145 | }, 146 | { 147 | "cell_type": "code", 148 | "execution_count": 7, 149 | "metadata": {}, 150 | "outputs": [ 151 | { 152 | "data": { 153 | "text/plain": [ 154 | "(reportinterval = 0, freqQ = 5, srcfieldfile = \"\", nsponge = 200, nthreads = 22)" 155 | ] 156 | }, 157 | "execution_count": 7, 158 | "metadata": {}, 159 | "output_type": "execute_result" 160 | } 161 | ], 162 | "source": [ 163 | "kwargs = (reportinterval = 0, freqQ=5, srcfieldfile=\"\", nsponge = 200, nthreads = div(Sys.CPU_THREADS,2))" 164 | ] 165 | }, 166 | { 167 | "cell_type": "markdown", 168 | "metadata": {}, 169 | "source": [ 170 | "## Note on scratch space for temporary files\n", 171 | "When dealing with multiple serialized nonlinear wavefields as in this example, we need to specify the location where scratch files will be written.\n", 172 | "\n", 173 | "You may need to change this to point to a temporary directory available on your system." 174 | ] 175 | }, 176 | { 177 | "cell_type": "code", 178 | "execution_count": 8, 179 | "metadata": {}, 180 | "outputs": [], 181 | "source": [ 182 | "@everywhere scratch = \"/mnt/scratch\"\n", 183 | "@assert isdir(scratch)" 184 | ] 185 | }, 186 | { 187 | "cell_type": "markdown", 188 | "metadata": {}, 189 | "source": [ 190 | "## Define single shot function to be run by the Scheduler\n", 191 | "Typically modeled data would be written to storage in this function, but we omit that detail here." 192 | ] 193 | }, 194 | { 195 | "cell_type": "code", 196 | "execution_count": 9, 197 | "metadata": {}, 198 | "outputs": [], 199 | "source": [ 200 | "@everywhere function modelshot(isrc, sx, _m; kwargs...)\n", 201 | " nz,nx,dz,dx = 176,851,20.0,20.0 \n", 202 | " @info \"modeling shot $(isrc) on $(gethostname()) with id $(myid())...\"\n", 203 | " F = JopNlProp2DAcoIsoDenQ_DEO2_FDTD(;\n", 204 | " b = ones(Float32,nz,nx),\n", 205 | " nthreads = div(Sys.CPU_THREADS,2),\n", 206 | " isinterior = true,\n", 207 | " ntrec = 1101,\n", 208 | " dtrec = 0.002,\n", 209 | " dtmod = 0.001,\n", 210 | " dz = dz,\n", 211 | " dx = dx,\n", 212 | " wavelet = WaveletCausalRicker(f=5.0),\n", 213 | " sx = sx[isrc],\n", 214 | " sz = dz,\n", 215 | " rx = dx*[0:1:nx-1;],\n", 216 | " rz = 2*dz*ones(length(0:1:nx-1)),\n", 217 | " srcfieldfile = joinpath(scratch, \"field-$isrc.$(randstring()).bin\"),\n", 218 | " reportinterval=1000,\n", 219 | " kwargs...)\n", 220 | " \n", 221 | " d = F*_m\n", 222 | " @info \"...done modeling shot $(isrc) on $(gethostname()) with id $(myid())\"\n", 223 | " @info \"extrema of shot $(isrc) is $(extrema(d))\"\n", 224 | "\n", 225 | " # typically write to cloud storage here\n", 226 | " nothing\n", 227 | "end" 228 | ] 229 | }, 230 | { 231 | "cell_type": "markdown", 232 | "metadata": {}, 233 | "source": [ 234 | "## Use Schedulers.epmap to dynamically schedule tasks to workers\n", 235 | "Note 1: you may see the dynamic nature of the scheduling in that the shot numbers might not necessarily map monotonically to the process identifiers of the workers.\n", 236 | "\n", 237 | "Note 2: we dont use the modeled data in any way here, we just demonstrate the modeling. In practice you would serialize the modeled data to local or cloud storage. " 238 | ] 239 | }, 240 | { 241 | "cell_type": "code", 242 | "execution_count": 10, 243 | "metadata": { 244 | "scrolled": true, 245 | "tags": [] 246 | }, 247 | "outputs": [ 248 | { 249 | "name": "stderr", 250 | "output_type": "stream", 251 | "text": [ 252 | "┌ Info: running task 1 on process 2; 2 workers total; 7 tasks left in task-pool.\n", 253 | "└ @ Schedulers /home/cvx/.julia/packages/Schedulers/05htU/src/Schedulers.jl:204\n", 254 | "┌ Info: running task 2 on process 3; 2 workers total; 6 tasks left in task-pool.\n", 255 | "└ @ Schedulers /home/cvx/.julia/packages/Schedulers/05htU/src/Schedulers.jl:204\n", 256 | "[ Info: modeling shot 1 on cbox-HC44rs2 with id 2...\n", 257 | "[ Info: modeling shot 2 on cbox-HC44rs2 with id 3...\n", 258 | "[ Info: ...done modeling shot 1 on cbox-HC44rs2 with id 2\n", 259 | "[ Info: ...done modeling shot 2 on cbox-HC44rs2 with id 3\n", 260 | "[ Info: extrema of shot 1 is (-59.979515f0, 109.98775f0)\n", 261 | "┌ Info: running task 3 on process 2; 2 workers total; 5 tasks left in task-pool.\n", 262 | "└ @ Schedulers /home/cvx/.julia/packages/Schedulers/05htU/src/Schedulers.jl:204\n", 263 | "[ Info: modeling shot 3 on cbox-HC44rs2 with id 2...\n", 264 | "[ Info: extrema of shot 2 is (-58.060192f0, 106.05541f0)\n", 265 | "┌ Info: running task 4 on process 3; 2 workers total; 4 tasks left in task-pool.\n", 266 | "└ @ Schedulers /home/cvx/.julia/packages/Schedulers/05htU/src/Schedulers.jl:204\n", 267 | "[ Info: modeling shot 4 on cbox-HC44rs2 with id 3...\n", 268 | "[ Info: ...done modeling shot 3 on cbox-HC44rs2 with id 2\n", 269 | "[ Info: extrema of shot 3 is (-59.74925f0, 109.51455f0)\n", 270 | "┌ Info: running task 5 on process 2; 2 workers total; 3 tasks left in task-pool.\n", 271 | "└ @ Schedulers /home/cvx/.julia/packages/Schedulers/05htU/src/Schedulers.jl:204\n", 272 | "[ Info: modeling shot 5 on cbox-HC44rs2 with id 2...\n", 273 | "[ Info: ...done modeling shot 4 on cbox-HC44rs2 with id 3\n", 274 | "[ Info: extrema of shot 4 is (-59.076214f0, 108.156715f0)\n", 275 | "┌ Info: running task 6 on process 3; 2 workers total; 2 tasks left in task-pool.\n", 276 | "└ @ Schedulers /home/cvx/.julia/packages/Schedulers/05htU/src/Schedulers.jl:204\n", 277 | "[ Info: modeling shot 6 on cbox-HC44rs2 with id 3...\n", 278 | "[ Info: ...done modeling shot 5 on cbox-HC44rs2 with id 2\n", 279 | "[ Info: extrema of shot 5 is (-59.076206f0, 108.15673f0)\n", 280 | "┌ Info: running task 7 on process 2; 2 workers total; 1 tasks left in task-pool.\n", 281 | "└ @ Schedulers /home/cvx/.julia/packages/Schedulers/05htU/src/Schedulers.jl:204\n", 282 | "[ Info: modeling shot 7 on cbox-HC44rs2 with id 2...\n", 283 | "[ Info: ...done modeling shot 6 on cbox-HC44rs2 with id 3\n", 284 | "[ Info: extrema of shot 6 is (-59.74925f0, 109.51465f0)\n", 285 | "┌ Info: running task 8 on process 3; 2 workers total; 0 tasks left in task-pool.\n", 286 | "└ @ Schedulers /home/cvx/.julia/packages/Schedulers/05htU/src/Schedulers.jl:204\n", 287 | "[ Info: modeling shot 8 on cbox-HC44rs2 with id 3...\n", 288 | "[ Info: ...done modeling shot 7 on cbox-HC44rs2 with id 2\n", 289 | "[ Info: extrema of shot 7 is (-58.060196f0, 106.05526f0)\n", 290 | "[ Info: ...done modeling shot 8 on cbox-HC44rs2 with id 3\n", 291 | "[ Info: extrema of shot 8 is (-59.98097f0, 109.977776f0)\n" 292 | ] 293 | } 294 | ], 295 | "source": [ 296 | "epmap(i->modelshot(i, sx, localpart(_m); kwargs...), 1:nshots)" 297 | ] 298 | }, 299 | { 300 | "cell_type": "markdown", 301 | "metadata": {}, 302 | "source": [ 303 | "## Remove workers" 304 | ] 305 | }, 306 | { 307 | "cell_type": "code", 308 | "execution_count": 11, 309 | "metadata": {}, 310 | "outputs": [], 311 | "source": [ 312 | "rmprocs(workers());" 313 | ] 314 | }, 315 | { 316 | "cell_type": "code", 317 | "execution_count": null, 318 | "metadata": {}, 319 | "outputs": [], 320 | "source": [] 321 | } 322 | ], 323 | "metadata": { 324 | "kernelspec": { 325 | "display_name": "Julia 1.5.2", 326 | "language": "julia", 327 | "name": "julia-1.5" 328 | }, 329 | "language_info": { 330 | "file_extension": ".jl", 331 | "mimetype": "application/julia", 332 | "name": "julia", 333 | "version": "1.5.2" 334 | } 335 | }, 336 | "nbformat": 4, 337 | "nbformat_minor": 4 338 | } 339 | -------------------------------------------------------------------------------- /50_fwi/10_add_slim_packages.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "## Constrained optimization\n", 15 | "For these constrained optimization examples the COFII framework nonlinear operators interoperate with optimization software provided by the SLIM group led by Felix Herrmann (previously at University of British Columbia and now at Georgia Tech). \n", 16 | "\n", 17 | "We employ the following three packages:\n", 18 | "- [SlimOptim](https://github.com/slimgroup/SlimOptim.jl) -- Package of optimization functions for large scale inversion\n", 19 | "\n", 20 | "- [JOLI](https://github.com/slimgroup/JOLI.jl) -- Julia framework for constructing matrix-free linear operators \n", 21 | "\n", 22 | "- [SetIntersectionProjection](https://github.com/slimgroup/SetIntersectionProjection.jl) -- Julia software for computing projections onto intersections of convex and non-convex constraint sets Documentation\n", 23 | "\n", 24 | "We did not install these in the setup notebook earlier, so install them now in the cell below.\n", 25 | "\n", 26 | "See also SLIM group examples at [ConstrainedFWIExamples](https://github.com/slimgroup/ConstrainedFWIExamples)." 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": null, 32 | "metadata": {}, 33 | "outputs": [], 34 | "source": [ 35 | "using Pkg\n", 36 | "Pkg.Registry.add(RegistrySpec(url=\"https://github.com/slimgroup/SLIMregistryJL.git\"))\n", 37 | "pkg\"add JOLI, SlimOptim, SetIntersectionProjection\"" 38 | ] 39 | } 40 | ], 41 | "metadata": { 42 | "kernelspec": { 43 | "display_name": "Julia 1.6.1", 44 | "language": "julia", 45 | "name": "julia-1.6" 46 | }, 47 | "language_info": { 48 | "file_extension": ".jl", 49 | "mimetype": "application/julia", 50 | "name": "julia", 51 | "version": "1.6.1" 52 | } 53 | }, 54 | "nbformat": 4, 55 | "nbformat_minor": 4 56 | } 57 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Examples is licensed under the MIT "Expat" License: 2 | 3 | > Copyright (c) 2020: Chevron U.S.A. Inc. 4 | > 5 | > Permission is hereby granted, free of charge, to any person obtaining 6 | > a copy of this software and associated documentation files (the 7 | > "Software"), to deal in the Software without restriction, including 8 | > without limitation the rights to use, copy, modify, merge, publish, 9 | > distribute, sublicense, and/or sell copies of the Software, and to 10 | > permit persons to whom the Software is furnished to do so, subject to 11 | > the following conditions: 12 | > 13 | > The above copyright notice and this permission notice shall be 14 | > included in all copies or substantial portions of the Software. 15 | > 16 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | > IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | > CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | > TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | > SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # COFII framework examples 3 | 4 | This series of jupyter notebooks demonstrates features of the `Chevron Optimization Framework for Imaging and Inversion`. 5 | 6 | * The notebooks are intended to be run in order. 7 | * Downstream notebooks may depend on artifacts created in previous notebooks. For example the Marmousi dataset is downloaded and processed in the series `20_marmousi_model_setup`, and used in subsequent notebooks. 8 | * Some notebooks may require reasonable HPC resources to run. For example the FWI and RTM examples can run for more than one hour, depending on what hardware you execute them on. 9 | 10 | 11 | ## Brief description of notebook series 12 | * `00_add_packages` adds and precompiles all packages used in these demos. 13 | * `10_jets_basics` introduction to `Jets` and `DistributedJets`. 14 | * `20_marmousi_model_setup` download the Marmousi model. 15 | * The Marmousi 2 model is provided by the Allied Geophysical Laboratory of the University of Houston, license and more information at the SEG wiki entry 16 | [AGL Elastic Marmousi](https://wiki.seg.org/wiki/AGL_Elastic_Marmousi). 17 | * If you run these notebooks you will have a copy of the license to review in the directory `20_marmousi_model_setup`. 18 | * `30_forward_modeling` static and dynamic scheduled modeling. 19 | * `40_sensitivity` generation of FWI sensitivity kernels, single trace and wavefield separation examples. 20 | * `50_fwi` 21 | * `01_fwi_L2.ipynb` contains a brute force Marmousi time domain FWI example using the `LBFGS` algorithm from `Optim.jl`, includes upsampling and downsampling models, data analysis, illumination compensation, very simple box constraints, and nonlinear optimization using `Optim.jl`. 22 | * `02_fwi_L2_dynamic.ipynb` contains a "cloud native" implementation of the previous notebook on the Azure cloud. 23 | * `10_add_slim_packages.ipynb, 11_constrained_fwi_pqn.ipynb, 12_constrained_fwi_spg.ipynb` contain constrained FWI examples that demonstrate interoperability with Georgia Tech SLIM group's julia software. 24 | * `60_rtm` brute force RTM of the Marmous FWI results, including data processing like applying a temporal mute, and image processing like a Laplacian filter to remove backscattered noise. Both static and dynamic scheduled examples are provided. 25 | --------------------------------------------------------------------------------