{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "af8fd14a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:45:00.150626Z",
     "iopub.status.busy": "2026-10-02T14:45:00.150362Z",
     "iopub.status.idle": "2026-10-02T14:45:00.156206Z",
     "shell.execute_reply": "2026-10-02T14:45:00.155326Z"
    },
    "papermill": {
     "duration": 0.009802,
     "end_time": "2026-10-02T14:45:00.156849+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:00.147047+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "active-ipynb",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "try:\n",
    "    from openmdao.utils.notebook_utils import notebook_mode  # noqa: F401\n",
    "except ImportError:\n",
    "    !python -m pip install openmdao[notebooks]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c0b73fad",
   "metadata": {
    "papermill": {
     "duration": 0.001852,
     "end_time": "2026-10-02T14:45:00.160867+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:00.159015+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# What is Julia?\n",
    "\n",
    "[Julia](https://julialang.org/) is a new-ish programming language targeting scientific and high-performance computing applications.\n",
    "Like Python or MATLAB, it is a dynamic language—you don't need to declare the types of variables like you would in C, C++, Fortran, etc..\n",
    "Unlike Python, it is a compiled language, as every function is compiled to machine code the first time it is called.\n",
    "The aim of Julia is to provide users with a programming language that combines the convience of Python or MATLAB with the speed of C or Fortran.\n",
    "The [official Julia documentation](https://docs.julialang.org/en/v1/) has [a nice page comparing Julia to other popular languages](https://docs.julialang.org/en/v1/manual/noteworthy-differences/) if you'd like to know more.\n",
    "\n",
    "One of the most attractive features of Julia for OpenMDAO users is its good support for automatic differentiation (AD).\n",
    "There are many (perhaps too many!) AD libraries available for the language, all with particular strengths and weaknesses.\n",
    "Happily, an excellent library called [DifferentiationInterface.jl](https://github.com/JuliaDiff/DifferentiationInterface.jl) exists which allows us to use any of these numerious AD library via a uniform API, which makes switching from one to another a matter of changing just one or two lines of code.\n",
    "\n",
    "# What is OpenMDAO.jl?\n",
    "<div class=\"alert alert-block alert-info\"> \n",
    "<b>NOTE</b> This page is a brief, Python-centric introduction to using Julia within OpenMDAO and OpenMDAO.jl in particular.\n",
    "Please check out <a href=\"https://flow.byu.edu/OpenMDAO.jl/dev/\">the OpenMDAO.jl docs</a> for all the details.\n",
    "</div>\n",
    "\n",
    "[OpenMDAO.jl](https://github.com/byuflowlab/OpenMDAO.jl) is a Python+Julia software package that allows users to create OpenMDAO `Component`s out of Julia code, and optionally use a Julia AD package to differentiate the `Component`.\n",
    "There are currently two possible approaches to using AD with Julia:\n",
    "1. Manual Approach: Users can write the equivalent of a `compute_partials` or `linearize` method in Julia that calls the desired AD library manually. This is quite flexible and conceptually straightforward, but requires more work on the part of the user to manage the complexities of translating the `inputs` and `outputs` vectors OpenMDAO provides to something that the AD library can work with.\n",
    "2. Automatic Approach: Users can write a relatively simple \"callback function\" that implements the math behind the `Component` they wish to create, and allow OpenMDAO.jl to call the AD for them. This is much less work for the user, but does require learning a bit more about the Julia language. This approach is also currently limited to creating `ExplicitComponent`s (though the callback function can contain implicitness via the [ImplicitAD.jl](https://github.com/byuflowlab/ImplicitAD.jl) package).\n",
    "\n",
    "This documentation will focus on approach number 2, the Automatic Approach, which consists of essentially three steps:\n",
    "\n",
    "1. Create a user-defined callback function\n",
    "2. Create an OpenMDAO.jl `AbstractADExplicitComp` `struct` that will keep track the user-defined function, the desired AD library, and other optional features like units, tags, etc..\n",
    "3. Pass the `AbstractADExplicitComp` to omjlcomps (\"OpenMDAO Julia Components\"), a Python library that knows how to create OpenMDAO `Component`s from an OpenMDAO.jl `AbstractADExplicitComp`.\n",
    "\n",
    "After completing those three steps, you'll be left with an OpenMDAO `Component` that you can include anywhere in an OpenMDAO model.\n",
    "We'll go through each of the three steps below. \n",
    "For more details, have a look at the [OpenMDAO.jl docs](https://flow.byu.edu/OpenMDAO.jl/dev/)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f95392f0",
   "metadata": {
    "papermill": {
     "duration": 0.093176,
     "end_time": "2026-10-02T14:45:00.439357+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:00.346181+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# Guided Tutorial\n",
    "\n",
    "## Step 1: The User-Defined Function\n",
    "The user-defined function *must* follow one of two forms: either it can be an \"in-place\" function that writes its outputs to an output vector, or it can be an \"out-of-place\" function that returns a single output vector.\n",
    "The function must be written in Julia, of course, and anything that happens inside the function is up to you, of course.\n",
    "Both the in-place and out-of-place form must also have a `params` argument that will contain inputs that are needed for the calculation, but won't be differentiated (the equivalent of OpenMDAO `options`).\n",
    "So, an example of an in-place function would be\n",
    "\n",
    "```julia\n",
    "function f_in_place!(Y, X, params)\n",
    "   # calculate stuff with X and params, storing result in Y\n",
    "   return nothing\n",
    "end\n",
    "```\n",
    "\n",
    "where `X` is the input vector and `Y` is the output vector.\n",
    "(The function doesn't have to return `nothing`, but any returned value will be ignored, so I like to include `return nothing` to make it clear that the return value doesn't matter.)\n",
    "An out-of-place function would look like\n",
    "\n",
    "```julia\n",
    "function f_out_of_place(X, params)\n",
    "   # calculate stuff with X and params, returning Y\n",
    "   return Y\n",
    "end\n",
    "```\n",
    "\n",
    "where again `X` is the input vector and `Y` is the output vector.\n",
    "\n",
    "Now, the `X` and `Y` arguments of those functions must not be plain Julia `Vector`s, but `ComponentVectors` from the [ComponentArrays.jl](https://github.com/jonniedie/ComponentArrays.jl) package.\n",
    "What are those?\n",
    "They are objects provided by the [ComponentArrays.jl](https://github.com/SciML/ComponentArrays.jl) package that act like `Vector`s, but allow the user to define names for each part (\"component\") of the vector.\n",
    "For example, we can do this from the Julia REPL:\n",
    "\n",
    "```julia\n",
    "julia> using ComponentArrays: ComponentVector\n",
    "\n",
    "julia> x1 = ComponentVector(foo=-1.0, bar=-2.0, baz=-3.0)\n",
    "ComponentVector{Float64}(foo = -1.0, bar = -2.0, baz = -3.0)\n",
    "\n",
    "julia> @show x1 x1[3] x1.foo x1[:foo]\n",
    "x1 = (foo = -1.0, bar = -2.0, baz = -3.0)\n",
    "x1[3] = -3.0\n",
    "x1.foo = -1.0\n",
    "x1[:foo] = -1.0\n",
    "-1.0\n",
    "\n",
    "julia> \n",
    "```\n",
    "\n",
    "Notice that we can get, say, the third value of `x1` the usual way (`x1[3]`), but also by referring to the `foo` field value via `x1.foo` and by indexing the `ComponentVector` with the symbol `:foo` (`x1[:foo]`).\n",
    "\n",
    "Each of the components in `x1` are scalars, but they don't have to be:\n",
    "\n",
    "```julia\n",
    "julia> x2 = ComponentVector(foo=-1.0, bar=1:4, baz=reshape(5:10, 2, 3))\n",
    "ComponentVector{Float64}(foo = -1.0, bar = [1.0, 2.0, 3.0, 4.0], baz = [5.0 7.0 9.0; 6.0 8.0 10.0])\n",
    "\n",
    "julia> @show x2 x2[:foo] x2[:bar] x2[:baz]\n",
    "x2 = (foo = -1.0, bar = [1.0, 2.0, 3.0, 4.0], baz = [5.0 7.0 9.0; 6.0 8.0 10.0])\n",
    "x2[:foo] = -1.0\n",
    "x2[:bar] = [1.0, 2.0, 3.0, 4.0]\n",
    "x2[:baz] = [5.0 7.0 9.0; 6.0 8.0 10.0]\n",
    "2×3 Matrix{Float64}:\n",
    " 5.0  7.0   9.0\n",
    " 6.0  8.0  10.0\n",
    "\n",
    "julia> \n",
    "```\n",
    "\n",
    "In `x2`, the `foo` component is a scalar, `bar` refers to a `Vector` (aka a 1D `Array`) and `baz` refers to a `Matrix` (aka a 2D Array).\n",
    "But `x2` still \"looks like\" a `Vector`:\n",
    "\n",
    "```julia\n",
    "julia> @show x2[3]  # will give the third value of `x2`, which happens to be the second value of x2[:bar]\n",
    "x2[3] = 2.0\n",
    "2.0\n",
    "\n",
    "julia> @show ndims(x2)  # Should be 1, since a Vector is 1-dimensional\n",
    "ndims(x2) = 1\n",
    "1\n",
    "\n",
    "julia> @show length(x2)  # length(x2) gives the total number of entries in `x2`, aka 1 + 4 + 2*3 = 11\n",
    "length(x2) = 11\n",
    "11\n",
    "\n",
    "julia> @show size(x2)  # size is a length-1 tuple since a Vector has just one dimension\n",
    "size(x2) = (11,)\n",
    "(11,)\n",
    "\n",
    "julia> \n",
    "```\n",
    "\n",
    "Now, how will we use `ComponentVector`s here?\n",
    "We'll use them to define the names and sizes of all the inputs and outputs to our component.\n",
    "For example, if we wanted to implement [the Paraboloid Example](../../basic_user_guide/single_disciplinary_optimization/first_analysis), which minimizes the function\n",
    "\n",
    "$$\n",
    "f(x,y) = (x-3.0)^2 + x \\cdot y + (y+4.0)^2 - 3.0\n",
    "$$\n",
    "\n",
    "using OpenMDAO.jl, we could create an input vector called `X_ca` that looks like this:\n",
    "\n",
    "```julia\n",
    "julia> X_ca = ComponentVector(x=1.0, y=1.0)\n",
    "ComponentVector{Float64}(x = 1.0, y = 1.0)\n",
    "\n",
    "julia> \n",
    "```\n",
    "\n",
    "That has two scalar components, `x` and `y`, that correspond to the two inputs to the paraboloid function.\n",
    "We could similarly use an output vector `Y_ca` that looks like this:\n",
    "\n",
    "```julia\n",
    "julia> Y_ca = ComponentVector(f_xy=0.0)\n",
    "ComponentVector{Float64}(f_xy = 0.0)\n",
    "\n",
    "julia> \n",
    "```\n",
    "\n",
    "with the single output `f_xy`.\n",
    "\n",
    "We could type in a callback function that implements the paraboloid equation above into the REPL if we want:\n",
    "\n",
    "```julia\n",
    "julia> function f_paraboloid!(Y, X, params)\n",
    "           # Get the inputs:\n",
    "           x = @view(X[:x])\n",
    "           y = @view(X[:y])\n",
    "           # Could also do this:\n",
    "           # x = X.x\n",
    "           # y = X.y\n",
    "           # or even this\n",
    "           # (; x, y) = X\n",
    "\n",
    "           # Get the output:\n",
    "           f_xy = @view(Y[:f_xy])\n",
    "           # Again, could also do this:\n",
    "           # f_xy = Y.f_xy\n",
    "           # or\n",
    "           # (; f_xy) = Y\n",
    "\n",
    "           # Do the calculation:\n",
    "           @. f_xy = (x - 3.0)^2 + x*y + (y + 4.0)^2 - 3.0\n",
    "\n",
    "           # No return value for in-place callback function.\n",
    "           return nothing\n",
    "       end\n",
    "f_paraboloid! (generic function with 1 method)\n",
    "\n",
    "julia> \n",
    "```\n",
    "\n",
    "And then test it out with the `X_ca` and `Y_ca` `ComponentVector`s we created earlier:\n",
    "\n",
    "```julia\n",
    "julia> f_paraboloid!(Y_ca, X_ca, nothing)\n",
    "\n",
    "julia> X_ca\n",
    "ComponentVector{Float64}(x = 1.0, y = 1.0)\n",
    "\n",
    "julia> Y_ca\n",
    "ComponentVector{Float64}(f_xy = 27.0)\n",
    "\n",
    "julia> \n",
    "```\n",
    "\n",
    "Some remarks about the callback function:\n",
    "\n",
    "* The `@view` macro is used when extracting the inputs and outputs from the `X_ca` and `Y_ca` `ComponentVectors`. This creates a view into the original ComponentVector, instead of a new array with a copy of the original data, which avoids unnecessary allocations and (for the outputs) allows modifications to the view to be reflected in the `Y_ca` array. In this example everything is a scalar, so no allocations would have happened anyway. But it doesn't hurt to use `@view`: it's a good habit to get into, and it allows us to use the `@.` broadcasting macro with the scalar `f_xy` output.\n",
    "* The `params` argument is not used in this example, but it is still required, since the code in OpenMDAO.jl will expect it. We provided a `nothing` value for it, but we could have given it anything and not changed the result of the function, of course.\n",
    "\n",
    "An out-of-place version of `f_paraboloid!` would look like this:\n",
    "\n",
    "```julia\n",
    "julia> function f_paraboloid(X, params)\n",
    "           x = @view(X[:x])\n",
    "           y = @view(X[:y])\n",
    "           f_xy = @. (x - 3.0)^2 + x*y + (y + 4.0)^2 - 3.0\n",
    "           return ComponentVector(f_xy=f_xy)\n",
    "       end\n",
    "f_paraboloid (generic function with 1 method)\n",
    "\n",
    "julia> f_paraboloid(X_ca, nothing)\n",
    "ComponentVector{Float64}(f_xy = 27.0)\n",
    "\n",
    "julia> \n",
    "```\n",
    "\n",
    "But we only need one or the other."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "188f93db",
   "metadata": {
    "papermill": {
     "duration": 0.002786,
     "end_time": "2026-10-02T14:45:00.444322+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:00.441536+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## Step 2: The OpenMDAO.jl `AbstractADExplicitComp`\n",
    "So far we've done a lot of typing in the Julia REPL, which is great for testing, but not great for writing code that you'll use more than once.\n",
    "Where should we store this Julia code that we're creating, and how will we call it from Python?\n",
    "This section will explain my favorite way to do that.\n",
    "Along the way we'll learn how to choose a Julia AD library, and create an `AbstractADExplicitComp` that will eventually be used to instantiate an `ExplicitComponent` that can be added to a OpenMDAO model.\n",
    "\n",
    "### A Julia Package for our Paraboloid\n",
    "We'll store our Julia code for the paraboloid component in a brand new Julia package called MyParaboloidPackage.\n",
    "Creating a new Julia package is very easy from the REPL: just type `]` to enter the [Pkg REPL](https://pkgdocs.julialang.org/v1/repl/) (look for the `pkg>` in the prompt to ensure you're in \"Pkg mode\"), then type `generate MyParaboloidPackage` to create the package:\n",
    "\n",
    "```julia\n",
    "(openmdao_jl_dev) pkg> generate MyParaboloidPackage\n",
    "  Generating  project MyParaboloidPackage:\n",
    "    MyParaboloidPackage/Project.toml\n",
    "    MyParaboloidPackage/src/MyParaboloidPackage.jl\n",
    "\n",
    "(openmdao_jl_dev) pkg> \n",
    "```\n",
    "\n",
    "(Keep this REPL open, as we'll be using it again later.)\n",
    "As the output suggests, running that command creates a directory called `MyParaboloidPackage` in the current working directory, along with two files.\n",
    "The `Project.toml` file contains metadata about the Julia project (name, version number, a UUID to distinguish it from other Julia packages, dependencies, etc.).\n",
    "The `src/MyParaboloidPackage.jl` contains the source code of the package, and at the moment looks like this:\n",
    "\n",
    "```julia\n",
    "module MyParaboloidPackage\n",
    "\n",
    "greet() = print(\"Hello World!\")\n",
    "\n",
    "end # module MyParaboloidPackage\n",
    "```\n",
    "\n",
    "We'll put our paraboloid code in `src/MyParaboloidPackage.jl` by copy-pasting the definition of `f_paraboloid!` into the file.\n",
    "Now it should look like this (with the `greet` function removed):\n",
    "\n",
    "```julia\n",
    "module MyParaboloidPackage\n",
    "\n",
    "function f_paraboloid!(Y, X, params)\n",
    "    x = @view(X[:x])\n",
    "    y = @view(X[:y])\n",
    "    f_xy = @view(Y[:f_xy])\n",
    "    @. f_xy = (x - 3.0)^2 + x*y + (y + 4.0)^2 - 3.0\n",
    "    return nothing\n",
    "end\n",
    "\n",
    "end # module MyParaboloidPackage\n",
    "```\n",
    "\n",
    "Now, let's see if we can create that `AbstractADExplicitComp` that we've been talking about.\n",
    "There are a few different flavors of `AbstractADExplicitComp` `struct`s that we could use, but for this example, we'll use `DenseADExplicitComp`, one that's designed for explicit components with a dense Jacobian.\n",
    "If we check out the [documentation for `DenseADExplicitComp` constructor](https://flow.byu.edu/OpenMDAO.jl/dev/reference/#OpenMDAOCore.DenseADExplicitComp-Union{Tuple{TAD},%20Tuple{TAD,%20Any,%20ComponentArrays.ComponentVector,%20ComponentArrays.ComponentVector}}%20where%20TAD%3C:ADTypes.AbstractADType), we'll see that we need four things to get this done:\n",
    "\n",
    "* An `ad_backend`, to be explained shortly\n",
    "* A callback function `f!`\n",
    "* `Y_ca`, a `ComponentVector` of outputs\n",
    "* `X_ca`, a `ComponentVector` of inputs\n",
    "\n",
    "In the previous section we learned how to create `X_ca` and `Y_ca`, and our callback function `f!` will be the `f_paraboloid!`.\n",
    "So the only missing ingrediant is the `ad_backend`.\n",
    "\n",
    "The `ad_backend` is a Julia object that will tell the `DenseADExplicitComp` which AD library we want to use to differentiate our component.\n",
    "The object must be a subtype of `AbstractADType`, an abstract type provided by the [ADTypes.jl](https://github.com/SciML/ADTypes.jl) package.\n",
    "That package is not part of the Julia Standard Library, so we'll need to install it.\n",
    "How do we do that?\n",
    "The easiest way is from the Julia Pkg REPL, aka the thing we used to generate the `MyParaboloidPackage` earlier.\n",
    "First, type `]` to ensure we're in the Pkg REPL (again, look for `pkg>` in the prompt), then do this:\n",
    "\n",
    "```\n",
    "(openmdao_jl_dev) pkg> activate ./MyParaboloidPackage\n",
    "  Activating project at `~/projects/openmdao_jl_dev/ved/OpenMDAO/openmdao/docs/openmdao_book/features/experimental/MyParaboloidPackage`\n",
    "\n",
    "(MyParaboloidPackage) pkg> \n",
    "```\n",
    "\n",
    "That \"activates\" the environment associated with MyParaboloidPackage, which tells the Julia Pkg package manager that we want to mess around with the dependencies of it and not some other environment or package.\n",
    "(The Pkg REPL reminds us which environment is \"active\" by changing the prompt to `(MyParaboloidPackage) pkg>`.) \n",
    "We can check the status of MyParaboloidPackage via the `status` command:\n",
    "\n",
    "```julia\n",
    "(MyParaboloidPackage) pkg> status\n",
    "Project MyParaboloidPackage v0.1.0\n",
    "Status `~/projects/openmdao_jl_dev/ved/OpenMDAO/openmdao/docs/openmdao_book/features/experimental/MyParaboloidPackage/Project.toml` (empty project)\n",
    "\n",
    "(MyParaboloidPackage) pkg> \n",
    "```\n",
    "\n",
    "Unsuprisingly there isn't much going on with it yet.\n",
    "\n",
    "The next step is to add the dependencies we need.\n",
    "We've already decided that we want ADTypes.jl, but we'll also need:\n",
    "\n",
    "* ComponentArrays.jl: for the `ComponentVector`s we'll provide to the `DenseADExplicitComp` constructor\n",
    "* OpenMDAOCore.jl: for the `DenseADExplicitComp` itself\n",
    "* ForwardDiff.jl: a forward-mode AD library that we'll use for this example\n",
    "\n",
    "So, let's install those using the `add` command from the Pkg REPL:\n",
    "\n",
    "```julia\n",
    "(MyParaboloidPackage) pkg> add ADTypes ComponentArrays OpenMDAOCore ForwardDiff\n",
    "   Resolving package versions...\n",
    "   Installed DifferentiationInterface ─ v0.7.14\n",
    "      Compat entries added for ADTypes, ComponentArrays, OpenMDAOCore, ForwardDiff\n",
    "    Updating `~/projects/openmdao_jl_dev/ved/OpenMDAO/openmdao/docs/openmdao_book/features/experimental/MyParaboloidPackage/Project.toml`\n",
    "  [47edcb42] + ADTypes v1.21.0\n",
    "  [b0b7db55] + ComponentArrays v0.15.31\n",
    "  [f6369f11] + ForwardDiff v1.3.1\n",
    "  [24d19c10] + OpenMDAOCore v0.3.3\n",
    "    Updating `~/projects/openmdao_jl_dev/ved/OpenMDAO/openmdao/docs/openmdao_book/features/experimental/MyParaboloidPackage/Manifest.toml`\n",
    "\n",
    "# Lots of output removed for clarity\n",
    "(MyParaboloidPackage) pkg> \n",
    "```\n",
    "\n",
    "Now if we try the `status` command again, we'll see this:\n",
    "\n",
    "```julia\n",
    "(MyParaboloidPackage) pkg> status\n",
    "Project MyParaboloidPackage v0.1.0\n",
    "Status `~/projects/openmdao_jl_dev/ved/OpenMDAO/openmdao/docs/openmdao_book/features/experimental/MyParaboloidPackage/Project.toml`\n",
    "  [47edcb42] ADTypes v1.21.0\n",
    "  [b0b7db55] ComponentArrays v0.15.31\n",
    "  [f6369f11] ForwardDiff v1.3.1\n",
    "  [24d19c10] OpenMDAOCore v0.3.3\n",
    "\n",
    "(MyParaboloidPackage) pkg> \n",
    "```\n",
    "\n",
    "That shows the dependencies of `MyParaboloidPackage`, and their version numbers.\n",
    "Excellent.\n",
    "\n",
    "Now we should have everything we need to create the `DenseADExplicitComp`.\n",
    "I think it's easiest to create a small \"helper function\" that we can call later that returns our `DenseADExplicitComp` that looks like this:\n",
    "\n",
    "```julia\n",
    "function get_paraboloid_comp()\n",
    "    ad_backend = ADTypes.AutoForwardDiff()\n",
    "    X_ca = ComponentVector(x=1.0, y=1.0)\n",
    "    Y_ca = ComponentVector(f_xy=0.0)\n",
    "    comp = OpenMDAOCore.DenseADExplicitComp(ad_backend, f_paraboloid!, Y_ca, X_ca)\n",
    "    return comp\n",
    "end\n",
    "```\n",
    "\n",
    "The `ADTypes.AutoForwardDiff()` means that we'll use [ForwardDiff.jl](https://github.com/JuliaDiff/ForwardDiff.jl), a forward-mode AD package, to differentiate our paraboloid.\n",
    "\n",
    "We'll add that function to `src/MyParaboloidPackage.jl`, along with some import statements that give us access to the packages we just installed.\n",
    "So now it should look like this:\n",
    "\n",
    "```julia\n",
    "module MyParaboloidPackage\n",
    "\n",
    "using ADTypes: ADTypes\n",
    "using ComponentArrays: ComponentVector\n",
    "using ForwardDiff: ForwardDiff\n",
    "using OpenMDAOCore: OpenMDAOCore\n",
    "\n",
    "function f_paraboloid!(Y, X, params)\n",
    "    x = @view(X[:x])\n",
    "    y = @view(X[:y])\n",
    "    f_xy = @view(Y[:f_xy])\n",
    "    @. f_xy = (x - 3.0)^2 + x*y + (y + 4.0)^2 - 3.0\n",
    "    return nothing\n",
    "end\n",
    "\n",
    "function get_paraboloid_comp()\n",
    "    ad_backend = ADTypes.AutoForwardDiff()\n",
    "    X_ca = ComponentVector(x=1.0, y=1.0)\n",
    "    Y_ca = ComponentVector(f_xy=0.0)\n",
    "    comp = OpenMDAOCore.DenseADExplicitComp(ad_backend, f_paraboloid!, Y_ca, X_ca)\n",
    "    return comp\n",
    "end\n",
    "\n",
    "end # module MyParaboloidPackage\n",
    "```\n",
    "\n",
    "We can try out the `get_paraboloid_comp` function from the normal Julia REPL (not the Pkg REPL—just backspace until you get the `julia> ` prompt back):\n",
    "\n",
    "```julia\n",
    "julia> using MyParaboloidPackage\n",
    "\n",
    "julia> comp = MyParaboloidPackage.get_paraboloid_comp()\n",
    "```\n",
    "\n",
    "You'll probibly see a bunch of output describing in excruciating detail all the type information associated with the `DenseADExplicitComp` we just created.\n",
    "But as long as you see something that starts with `OpenMDAOCore.DenseADExplicitComp`, we should be good.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "69ff47f1",
   "metadata": {
    "papermill": {
     "duration": 0.002619,
     "end_time": "2026-10-02T14:45:00.448899+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:00.446280+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## Step 3: The `omjlcomps.JuliaExplicitComp`\n",
    "So far we have created a Julia callback function and a `DenseADExplicitComp` for our paraboloid.\n",
    "The last step is to turn that `DenseADExplicitComp` into something we can actually incorporate into an OpenMDAO model.\n",
    "We'll do that using omjlcomps, a Python package that's part of OpenMDAO.jl.\n",
    "\n",
    "But first, we need to figure out a nice way of telling Python about our Julia code.\n",
    "The best way of doing that is using [juliapkg](https://github.com/JuliaPy/pyjuliapkg), a Python package that allows us to add Julia dependencies to a Python package.\n",
    "We could install it manually ourselves using `pip install juliapkg`, but if instead we install OpenMDAO with the \"julia\" extra, we'll get it automatically:\n",
    "\n",
    "```bash\n",
    "$ pip install openmdao[julia]\n",
    "```\n",
    "\n",
    "We'll do that from here in a Jupyter notebook using this command:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "11b3fe8b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:45:00.466340Z",
     "iopub.status.busy": "2026-10-02T14:45:00.466059Z",
     "iopub.status.idle": "2026-10-02T14:45:01.364020Z",
     "shell.execute_reply": "2026-10-02T14:45:01.362772Z"
    },
    "papermill": {
     "duration": 0.90932,
     "end_time": "2026-10-02T14:45:01.367276+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:00.457956+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: openmdao[julia] in /home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages (3.45.2.dev0)\r\n",
      "Requirement already satisfied: networkx>=3.3 in /home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages (from openmdao[julia]) (3.6.1)\r\n",
      "Requirement already satisfied: numpy!=2.4.0,>=2.0 in /home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages (from openmdao[julia]) (2.4.6)\r\n",
      "Requirement already satisfied: packaging in /home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages (from openmdao[julia]) (26.3)\r\n",
      "Requirement already satisfied: requests in /home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages (from openmdao[julia]) (2.34.2)\r\n",
      "Requirement already satisfied: scipy>=1.13 in /home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages (from openmdao[julia]) (1.17.0)\r\n",
      "Requirement already satisfied: omjlcomps>=0.2.6 in /home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages (from openmdao[julia]) (0.2.7)\r\n",
      "Requirement already satisfied: juliapkg~=0.1.10 in /home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages (from omjlcomps>=0.2.6->openmdao[julia]) (0.1.27)\r\n",
      "Requirement already satisfied: juliacall~=0.9.13 in /home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages (from omjlcomps>=0.2.6->openmdao[julia]) (0.9.36)\r\n",
      "Requirement already satisfied: filelock<4.0,>=3.16 in /home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages (from juliapkg~=0.1.10->omjlcomps>=0.2.6->openmdao[julia]) (3.32.2)\r\n",
      "Requirement already satisfied: semver<4.0,>=3.0 in /home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages (from juliapkg~=0.1.10->omjlcomps>=0.2.6->openmdao[julia]) (3.1.0)\r\n",
      "Requirement already satisfied: tomli<3.0,>=2.0 in /home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages (from juliapkg~=0.1.10->omjlcomps>=0.2.6->openmdao[julia]) (2.4.1)\r\n",
      "Requirement already satisfied: tomlkit<0.16,>=0.13.3 in /home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages (from juliapkg~=0.1.10->omjlcomps>=0.2.6->openmdao[julia]) (0.15.1)\r\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: charset_normalizer<4,>=2 in /home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages (from requests->openmdao[julia]) (3.4.9)\r\n",
      "Requirement already satisfied: idna<4,>=2.5 in /home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages (from requests->openmdao[julia]) (3.18)\r\n",
      "Requirement already satisfied: urllib3<3,>=1.26 in /home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages (from requests->openmdao[julia]) (2.7.0)\r\n",
      "Requirement already satisfied: certifi>=2023.5.7 in /home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages (from requests->openmdao[julia]) (2026.7.22)\r\n"
     ]
    }
   ],
   "source": [
    "!pip install openmdao[julia]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ac00d1b7",
   "metadata": {
    "papermill": {
     "duration": 0.005154,
     "end_time": "2026-10-02T14:45:01.376962+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:01.371808+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "Now, we need to use juliapkg to tell our Python environment about MyParaboloidPackage.\n",
    "We do that by creating a file called `juliapkg.json` in our working directory that points to MyParaboloidPackage:\n",
    "\n",
    "```json\n",
    "{\"packages\": {\n",
    "    \"MyParaboloidPackage\": {\"uuid\": \"a013c6e3-dc76-40b3-894d-62618f778e16\", \"dev\": true, \"path\": \"./MyParaboloidPackage\"}\n",
    "    }\n",
    "}\n",
    "```\n",
    "\n",
    "(To get the correct value for the `\"uuid\"` field, copy what's in the `MyParaboloidPackage/Project.toml` file.\n",
    "It will be different from what is listed above if you're trying out these commands yourself.)\n",
    "\n",
    "That tells juliapkg about MyParaboloidPackage.\n",
    "The `\"dev\": true` means that the package will be installed in \"develop\" mode, meaning any changes in the package will be reflected in code that calls it—it's the equivalent of `pip install -e` or `pip install --editable` in Python.\n",
    "\n",
    "`juliapkg` searches for `juliapkg.json` files in, among other places, each entry in `sys.path`.\n",
    "This is great for adding Julia dependencies to Python packages: you can add a `juliapkg.json` to your Python source, and `juliapkg` will find it automatically if your Python package is installed in the current environment.\n",
    "It also works well for Python scripts run from the command line: since Python automatically adds the directory of the script to `sys.path`, we could place the `juliapkg.json` file in the same directory as the run script and it should also be found by `juliapkg`.\n",
    "But it's not-so-great for Jupyter notebooks like this one.\n",
    "So we'll have to manually add what we think is the current working directory to `sys.path` and cross our fingers.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "ed67bfa8",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:45:01.457922Z",
     "iopub.status.busy": "2026-10-02T14:45:01.454853Z",
     "iopub.status.idle": "2026-10-02T14:45:01.462093Z",
     "shell.execute_reply": "2026-10-02T14:45:01.461543Z"
    },
    "papermill": {
     "duration": 0.013836,
     "end_time": "2026-10-02T14:45:01.464018+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:01.450182+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/_executed_book/features/experimental\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "import sys\n",
    "d = os.getcwd()\n",
    "sys.path.append(d)\n",
    "print(sys.path[-1])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1f565ef5",
   "metadata": {
    "papermill": {
     "duration": 0.002572,
     "end_time": "2026-10-02T14:45:01.468946+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:01.466374+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "Next, we'll create a small julia file in the current working directory that will import the `get_paraboloid_comp` function that we just added to `MyParaboloidPackage` called `paraboloid.jl`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "d0c7d60e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:45:01.480414Z",
     "iopub.status.busy": "2026-10-02T14:45:01.480239Z",
     "iopub.status.idle": "2026-10-02T14:45:01.784267Z",
     "shell.execute_reply": "2026-10-02T14:45:01.783792Z"
    },
    "papermill": {
     "duration": 0.311777,
     "end_time": "2026-10-02T14:45:01.785287+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:01.473510+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<style>pre { line-height: 125%; }\n",
       "td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\n",
       "span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\n",
       "td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n",
       "span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n",
       ".output_html .hll { background-color: #ffffcc }\n",
       ".output_html { background: #f8f8f8; }\n",
       ".output_html .c { color: #3D7B7B; font-style: italic } /* Comment */\n",
       ".output_html .err { border: 1px solid #F00 } /* Error */\n",
       ".output_html .k { color: #008000; font-weight: bold } /* Keyword */\n",
       ".output_html .o { color: #666 } /* Operator */\n",
       ".output_html .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */\n",
       ".output_html .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */\n",
       ".output_html .cp { color: #9C6500 } /* Comment.Preproc */\n",
       ".output_html .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */\n",
       ".output_html .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */\n",
       ".output_html .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */\n",
       ".output_html .gd { color: #A00000 } /* Generic.Deleted */\n",
       ".output_html .ge { font-style: italic } /* Generic.Emph */\n",
       ".output_html .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */\n",
       ".output_html .gr { color: #E40000 } /* Generic.Error */\n",
       ".output_html .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
       ".output_html .gi { color: #008400 } /* Generic.Inserted */\n",
       ".output_html .go { color: #717171 } /* Generic.Output */\n",
       ".output_html .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
       ".output_html .gs { font-weight: bold } /* Generic.Strong */\n",
       ".output_html .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
       ".output_html .gt { color: #04D } /* Generic.Traceback */\n",
       ".output_html .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
       ".output_html .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
       ".output_html .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
       ".output_html .kp { color: #008000 } /* Keyword.Pseudo */\n",
       ".output_html .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
       ".output_html .kt { color: #B00040 } /* Keyword.Type */\n",
       ".output_html .m { color: #666 } /* Literal.Number */\n",
       ".output_html .s { color: #BA2121 } /* Literal.String */\n",
       ".output_html .na { color: #687822 } /* Name.Attribute */\n",
       ".output_html .nb { color: #008000 } /* Name.Builtin */\n",
       ".output_html .nc { color: #00F; font-weight: bold } /* Name.Class */\n",
       ".output_html .no { color: #800 } /* Name.Constant */\n",
       ".output_html .nd { color: #A2F } /* Name.Decorator */\n",
       ".output_html .ni { color: #717171; font-weight: bold } /* Name.Entity */\n",
       ".output_html .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */\n",
       ".output_html .nf { color: #00F } /* Name.Function */\n",
       ".output_html .nl { color: #767600 } /* Name.Label */\n",
       ".output_html .nn { color: #00F; font-weight: bold } /* Name.Namespace */\n",
       ".output_html .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
       ".output_html .nv { color: #19177C } /* Name.Variable */\n",
       ".output_html .ow { color: #A2F; font-weight: bold } /* Operator.Word */\n",
       ".output_html .w { color: #BBB } /* Text.Whitespace */\n",
       ".output_html .mb { color: #666 } /* Literal.Number.Bin */\n",
       ".output_html .mf { color: #666 } /* Literal.Number.Float */\n",
       ".output_html .mh { color: #666 } /* Literal.Number.Hex */\n",
       ".output_html .mi { color: #666 } /* Literal.Number.Integer */\n",
       ".output_html .mo { color: #666 } /* Literal.Number.Oct */\n",
       ".output_html .sa { color: #BA2121 } /* Literal.String.Affix */\n",
       ".output_html .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
       ".output_html .sc { color: #BA2121 } /* Literal.String.Char */\n",
       ".output_html .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
       ".output_html .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
       ".output_html .s2 { color: #BA2121 } /* Literal.String.Double */\n",
       ".output_html .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */\n",
       ".output_html .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
       ".output_html .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */\n",
       ".output_html .sx { color: #008000 } /* Literal.String.Other */\n",
       ".output_html .sr { color: #A45A77 } /* Literal.String.Regex */\n",
       ".output_html .s1 { color: #BA2121 } /* Literal.String.Single */\n",
       ".output_html .ss { color: #19177C } /* Literal.String.Symbol */\n",
       ".output_html .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
       ".output_html .fm { color: #00F } /* Name.Function.Magic */\n",
       ".output_html .vc { color: #19177C } /* Name.Variable.Class */\n",
       ".output_html .vg { color: #19177C } /* Name.Variable.Global */\n",
       ".output_html .vi { color: #19177C } /* Name.Variable.Instance */\n",
       ".output_html .vm { color: #19177C } /* Name.Variable.Magic */\n",
       ".output_html .il { color: #666 } /* Literal.Number.Integer.Long */</style><div class=\"highlight\"><pre><span></span><span class=\"k\">using</span><span class=\"w\"> </span><span class=\"n\">MyParaboloidPackage</span><span class=\"o\">:</span><span class=\"w\"> </span><span class=\"n\">get_paraboloid_comp</span>\n",
       "</pre></div>\n"
      ],
      "text/latex": [
       "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
       "\\PY{k}{using}\\PY{+w}{ }\\PY{n}{MyParaboloidPackage}\\PY{o}{:}\\PY{+w}{ }\\PY{n}{get\\PYZus{}paraboloid\\PYZus{}comp}\n",
       "\\end{Verbatim}\n"
      ],
      "text/plain": [
       "using MyParaboloidPackage: get_paraboloid_comp"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import display, Code\n",
    "display(Code(os.path.join(d, \"paraboloid.jl\")))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "404ba2d6",
   "metadata": {
    "papermill": {
     "duration": 0.012153,
     "end_time": "2026-10-02T14:45:01.799916+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:01.787763+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "Now we'll create another small file, this time a Python one, called `paraboloid.py` that will include that `paraboloid.jl` julia file using JuliaCall, a Python package for calling Julia code that was automatically installed when we did `pip install openmdao[julia]`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "c69fefdc",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:45:01.804648Z",
     "iopub.status.busy": "2026-10-02T14:45:01.804428Z",
     "iopub.status.idle": "2026-10-02T14:45:01.838227Z",
     "shell.execute_reply": "2026-10-02T14:45:01.837727Z"
    },
    "papermill": {
     "duration": 0.036719,
     "end_time": "2026-10-02T14:45:01.838638+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:01.801919+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<style>pre { line-height: 125%; }\n",
       "td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\n",
       "span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\n",
       "td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n",
       "span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n",
       ".output_html .hll { background-color: #ffffcc }\n",
       ".output_html { background: #f8f8f8; }\n",
       ".output_html .c { color: #3D7B7B; font-style: italic } /* Comment */\n",
       ".output_html .err { border: 1px solid #F00 } /* Error */\n",
       ".output_html .k { color: #008000; font-weight: bold } /* Keyword */\n",
       ".output_html .o { color: #666 } /* Operator */\n",
       ".output_html .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */\n",
       ".output_html .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */\n",
       ".output_html .cp { color: #9C6500 } /* Comment.Preproc */\n",
       ".output_html .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */\n",
       ".output_html .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */\n",
       ".output_html .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */\n",
       ".output_html .gd { color: #A00000 } /* Generic.Deleted */\n",
       ".output_html .ge { font-style: italic } /* Generic.Emph */\n",
       ".output_html .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */\n",
       ".output_html .gr { color: #E40000 } /* Generic.Error */\n",
       ".output_html .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
       ".output_html .gi { color: #008400 } /* Generic.Inserted */\n",
       ".output_html .go { color: #717171 } /* Generic.Output */\n",
       ".output_html .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
       ".output_html .gs { font-weight: bold } /* Generic.Strong */\n",
       ".output_html .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
       ".output_html .gt { color: #04D } /* Generic.Traceback */\n",
       ".output_html .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
       ".output_html .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
       ".output_html .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
       ".output_html .kp { color: #008000 } /* Keyword.Pseudo */\n",
       ".output_html .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
       ".output_html .kt { color: #B00040 } /* Keyword.Type */\n",
       ".output_html .m { color: #666 } /* Literal.Number */\n",
       ".output_html .s { color: #BA2121 } /* Literal.String */\n",
       ".output_html .na { color: #687822 } /* Name.Attribute */\n",
       ".output_html .nb { color: #008000 } /* Name.Builtin */\n",
       ".output_html .nc { color: #00F; font-weight: bold } /* Name.Class */\n",
       ".output_html .no { color: #800 } /* Name.Constant */\n",
       ".output_html .nd { color: #A2F } /* Name.Decorator */\n",
       ".output_html .ni { color: #717171; font-weight: bold } /* Name.Entity */\n",
       ".output_html .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */\n",
       ".output_html .nf { color: #00F } /* Name.Function */\n",
       ".output_html .nl { color: #767600 } /* Name.Label */\n",
       ".output_html .nn { color: #00F; font-weight: bold } /* Name.Namespace */\n",
       ".output_html .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
       ".output_html .nv { color: #19177C } /* Name.Variable */\n",
       ".output_html .ow { color: #A2F; font-weight: bold } /* Operator.Word */\n",
       ".output_html .w { color: #BBB } /* Text.Whitespace */\n",
       ".output_html .mb { color: #666 } /* Literal.Number.Bin */\n",
       ".output_html .mf { color: #666 } /* Literal.Number.Float */\n",
       ".output_html .mh { color: #666 } /* Literal.Number.Hex */\n",
       ".output_html .mi { color: #666 } /* Literal.Number.Integer */\n",
       ".output_html .mo { color: #666 } /* Literal.Number.Oct */\n",
       ".output_html .sa { color: #BA2121 } /* Literal.String.Affix */\n",
       ".output_html .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
       ".output_html .sc { color: #BA2121 } /* Literal.String.Char */\n",
       ".output_html .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
       ".output_html .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
       ".output_html .s2 { color: #BA2121 } /* Literal.String.Double */\n",
       ".output_html .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */\n",
       ".output_html .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
       ".output_html .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */\n",
       ".output_html .sx { color: #008000 } /* Literal.String.Other */\n",
       ".output_html .sr { color: #A45A77 } /* Literal.String.Regex */\n",
       ".output_html .s1 { color: #BA2121 } /* Literal.String.Single */\n",
       ".output_html .ss { color: #19177C } /* Literal.String.Symbol */\n",
       ".output_html .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
       ".output_html .fm { color: #00F } /* Name.Function.Magic */\n",
       ".output_html .vc { color: #19177C } /* Name.Variable.Class */\n",
       ".output_html .vg { color: #19177C } /* Name.Variable.Global */\n",
       ".output_html .vi { color: #19177C } /* Name.Variable.Instance */\n",
       ".output_html .vm { color: #19177C } /* Name.Variable.Magic */\n",
       ".output_html .il { color: #666 } /* Literal.Number.Integer.Long */</style><div class=\"highlight\"><pre><span></span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">os</span>\n",
       "\n",
       "<span class=\"c1\"># Create a new Julia module that will hold all the Julia code imported into this Python module.</span>\n",
       "<span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">juliacall</span>\n",
       "<span class=\"n\">jl</span> <span class=\"o\">=</span> <span class=\"n\">juliacall</span><span class=\"o\">.</span><span class=\"n\">newmodule</span><span class=\"p\">(</span><span class=\"s2\">&quot;ParaboloidComponentsStub&quot;</span><span class=\"p\">)</span>\n",
       "\n",
       "<span class=\"c1\"># Get the directory this file is in, then include the `paraboloid.jl` Julia source code.</span>\n",
       "<span class=\"n\">d</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">dirname</span><span class=\"p\">(</span><span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"vm\">__file__</span><span class=\"p\">))</span>\n",
       "<span class=\"n\">jl</span><span class=\"o\">.</span><span class=\"n\">include</span><span class=\"p\">(</span><span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">d</span><span class=\"p\">,</span> <span class=\"s2\">&quot;paraboloid.jl&quot;</span><span class=\"p\">))</span>\n",
       "<span class=\"c1\"># Now we have access to everything in `paraboloid.jl` in the `jl` object.</span>\n",
       "\n",
       "<span class=\"n\">get_paraboloid_comp</span> <span class=\"o\">=</span> <span class=\"n\">jl</span><span class=\"o\">.</span><span class=\"n\">get_paraboloid_comp</span>\n",
       "</pre></div>\n"
      ],
      "text/latex": [
       "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
       "\\PY{k+kn}{import}\\PY{+w}{ }\\PY{n+nn}{os}\n",
       "\n",
       "\\PY{c+c1}{\\PYZsh{} Create a new Julia module that will hold all the Julia code imported into this Python module.}\n",
       "\\PY{k+kn}{import}\\PY{+w}{ }\\PY{n+nn}{juliacall}\n",
       "\\PY{n}{jl} \\PY{o}{=} \\PY{n}{juliacall}\\PY{o}{.}\\PY{n}{newmodule}\\PY{p}{(}\\PY{l+s+s2}{\\PYZdq{}}\\PY{l+s+s2}{ParaboloidComponentsStub}\\PY{l+s+s2}{\\PYZdq{}}\\PY{p}{)}\n",
       "\n",
       "\\PY{c+c1}{\\PYZsh{} Get the directory this file is in, then include the `paraboloid.jl` Julia source code.}\n",
       "\\PY{n}{d} \\PY{o}{=} \\PY{n}{os}\\PY{o}{.}\\PY{n}{path}\\PY{o}{.}\\PY{n}{dirname}\\PY{p}{(}\\PY{n}{os}\\PY{o}{.}\\PY{n}{path}\\PY{o}{.}\\PY{n}{abspath}\\PY{p}{(}\\PY{n+nv+vm}{\\PYZus{}\\PYZus{}file\\PYZus{}\\PYZus{}}\\PY{p}{)}\\PY{p}{)}\n",
       "\\PY{n}{jl}\\PY{o}{.}\\PY{n}{include}\\PY{p}{(}\\PY{n}{os}\\PY{o}{.}\\PY{n}{path}\\PY{o}{.}\\PY{n}{join}\\PY{p}{(}\\PY{n}{d}\\PY{p}{,} \\PY{l+s+s2}{\\PYZdq{}}\\PY{l+s+s2}{paraboloid.jl}\\PY{l+s+s2}{\\PYZdq{}}\\PY{p}{)}\\PY{p}{)}\n",
       "\\PY{c+c1}{\\PYZsh{} Now we have access to everything in `paraboloid.jl` in the `jl` object.}\n",
       "\n",
       "\\PY{n}{get\\PYZus{}paraboloid\\PYZus{}comp} \\PY{o}{=} \\PY{n}{jl}\\PY{o}{.}\\PY{n}{get\\PYZus{}paraboloid\\PYZus{}comp}\n",
       "\\end{Verbatim}\n"
      ],
      "text/plain": [
       "import os\n",
       "\n",
       "# Create a new Julia module that will hold all the Julia code imported into this Python module.\n",
       "import juliacall\n",
       "jl = juliacall.newmodule(\"ParaboloidComponentsStub\")\n",
       "\n",
       "# Get the directory this file is in, then include the `paraboloid.jl` Julia source code.\n",
       "d = os.path.dirname(os.path.abspath(__file__))\n",
       "jl.include(os.path.join(d, \"paraboloid.jl\"))\n",
       "# Now we have access to everything in `paraboloid.jl` in the `jl` object.\n",
       "\n",
       "get_paraboloid_comp = jl.get_paraboloid_comp"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "display(Code(os.path.join(d, \"paraboloid.py\")))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "23702a74",
   "metadata": {
    "papermill": {
     "duration": 0.006512,
     "end_time": "2026-10-02T14:45:01.847414+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:01.840902+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "Now we should be able to use omjlcomps (another Python package that was installed as a side effect of `pip install openmdao[julia]`) to create a `JuliaExplicitComp`.\n",
    "We do this by first calling `get_paraboloid_comp` to get the `DenseADExplicitComp` `struct` we created, then pass it as the `jlcomp` argument to `JuliaExplicitComp`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "4fe2949e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:45:01.852208Z",
     "iopub.status.busy": "2026-10-02T14:45:01.852017Z",
     "iopub.status.idle": "2026-10-02T14:46:31.937454Z",
     "shell.execute_reply": "2026-10-02T14:46:31.936976Z"
    },
    "papermill": {
     "duration": 90.08906,
     "end_time": "2026-10-02T14:46:31.938502+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:01.849442+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[juliapkg] Found dependencies: /home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages/juliacall/juliapkg.json\n",
      "[juliapkg] Found dependencies: /home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages/juliapkg/juliapkg.json\n",
      "[juliapkg] Found dependencies: /home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages/omjlcomps/juliapkg.json\n",
      "[juliapkg] Found dependencies: /home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/_executed_book/features/experimental/juliapkg.json\n",
      "[juliapkg] Locating Julia ^1.10.3\n",
      "[juliapkg] Using Julia 1.13.1 at /opt/hostedtoolcache/julia/1.13.1/x64/bin/julia\n",
      "[juliapkg] Finding libjulia and bindir:\n",
      "           | using Libdl\n",
      "           | print(abspath(Libdl.dlpath(\"libjulia\")), '\\0', Sys.BINDIR)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[juliapkg] Using Julia project at /home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/julia_env\n",
      "[juliapkg] Writing Project.toml:\n",
      "           | [deps]\n",
      "           | PythonCall = \"6099a3de-0909-46bc-b1f4-468b9a2dfc0d\"\n",
      "           | OpenSSL_jll = \"458c3c95-2e84-50aa-8efc-19380b2a3a95\"\n",
      "           | OpenMDAOCore = \"24d19c10-6eee-420f-95df-4537264b2753\"\n",
      "           | LinearAlgebra = \"37e2e46d-f89d-539d-b4ee-838fcccc9c8e\"\n",
      "           | MyParaboloidPackage = \"a013c6e3-dc76-40b3-894d-62618f778e16\"\n",
      "           | \n",
      "           | [compat]\n",
      "           | PythonCall = \"=0.9.36\"\n",
      "           | OpenSSL_jll = \"3.0.0 - 3.6\"\n",
      "           | OpenMDAOCore = \"^0.3.2\"\n",
      "           | \n",
      "           | [preferences]\n",
      "[juliapkg] Installing packages:\n",
      "           | import Pkg\n",
      "           | Pkg.Registry.update()\n",
      "           | Pkg.develop([\n",
      "           |   Pkg.PackageSpec(name=\"MyParaboloidPackage\", uuid=\"a013c6e3-dc76-40b3-894d-62618f778e16\", path=raw\"/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/_executed_book/features/experimental/MyParaboloidPackage\"),\n",
      "           | ])\n",
      "           | Pkg.add([\n",
      "           |   Pkg.PackageSpec(name=\"PythonCall\", uuid=\"6099a3de-0909-46bc-b1f4-468b9a2dfc0d\"),\n",
      "           |   Pkg.PackageSpec(name=\"OpenSSL_jll\", uuid=\"458c3c95-2e84-50aa-8efc-19380b2a3a95\"),\n",
      "           |   Pkg.PackageSpec(name=\"OpenMDAOCore\", uuid=\"24d19c10-6eee-420f-95df-4537264b2753\"),\n",
      "           |   Pkg.PackageSpec(name=\"LinearAlgebra\", uuid=\"37e2e46d-f89d-539d-b4ee-838fcccc9c8e\"),\n",
      "           | ])\n",
      "           | Pkg.resolve()\n",
      "           | Pkg.precompile()\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m\u001b[1m  Installing\u001b[22m\u001b[39m known registries into `~/.julia`\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m\u001b[1m       Added\u001b[22m\u001b[39m `General` registry to ~/.julia/registries\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m\u001b[1m   Resolving\u001b[22m\u001b[39m package versions...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m CommonWorldInvalidations ──── v1.2.2\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m ForwardDiff ───────────────── v1.4.6\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m DataStructures ────────────── v0.18.22\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m SparseMatrixColorings ─────── v0.4.28\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m Adapt ─────────────────────── v4.7.1\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m Functors ──────────────────── v0.5.3\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m micromamba_jll ────────────── v2.3.1+0\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m OrderedCollections ────────── v1.8.2\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m ArrayInterface ────────────── v7.30.2\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m MacroTools ────────────────── v0.5.16\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m DiffResults ───────────────── v1.1.0\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m ComponentArrays ───────────── v0.15.50\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m UnsafePointers ────────────── v1.0.0\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m ConstructionBase ──────────── v1.6.0\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m Compat ────────────────────── v4.18.1\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m DataAPI ───────────────────── v1.16.0\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m IteratorInterfaceExtensions ─ v1.0.0\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m CondaPkg ──────────────────── v0.2.36\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m PrecompileTools ───────────── v1.3.4\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m StructUtils ───────────────── v2.9.2\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m ChainRulesCore ────────────── v1.26.1\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m OpenMDAOCore ──────────────── v0.3.3\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m CommonSubexpressions ──────── v0.3.1\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m MicroMamba ────────────────── v0.1.15\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m DataValueInterfaces ───────── v1.0.0\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m NaNMath ───────────────────── v1.1.4\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m IrrationalConstants ───────── v0.2.6\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m SciMLPublic ───────────────── v1.3.0\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m StaticArraysCore ──────────── v1.4.4\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m Pidfile ───────────────────── v1.3.0\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m LogExpFunctions ───────────── v1.0.2\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m UnitfulAngles ─────────────── v0.7.2\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m StaticArrayInterface ──────── v1.10.0\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m DiffRules ─────────────────── v1.16.0\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m Parsers ───────────────────── v3.0.0\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m JSON ──────────────────────── v1.10.0\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m OpenSpecFun_jll ───────────── v0.5.6+0\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m Tables ────────────────────── v1.14.0\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m Unitful ───────────────────── v1.29.0\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m SpecialFunctions ──────────── v2.9.0\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m Preferences ───────────────── v1.6.0\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m pixi_jll ──────────────────── v0.76.2+0\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m Static ────────────────────── v1.4.6\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m IfElse ────────────────────── v0.1.1\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m ADTypes ───────────────────── v1.24.0\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m DifferentiationInterface ──── v0.7.21\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m Scratch ───────────────────── v1.3.0\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m JLLWrappers ───────────────── v1.8.0\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m TableTraits ───────────────── v1.0.1\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m PythonCall ────────────────── v0.9.36\n",
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m DocStringExtensions ───────── v0.9.5\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m\u001b[1m  Installing\u001b[22m\u001b[39m 1 artifacts\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m\u001b[1m   Installed\u001b[22m\u001b[39m artifact OpenSpecFun 105.4 KiB\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m\u001b[1m    Updating\u001b[22m\u001b[39m `~/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/julia_env/Project.toml`\n",
      "  \u001b[90m[a013c6e3] \u001b[39m\u001b[92m+ MyParaboloidPackage v0.1.0 `~/work/OpenMDAO/OpenMDAO/openmdao/docs/_executed_book/features/experimental/MyParaboloidPackage`\u001b[39m\n",
      "  \u001b[90m[24d19c10] \u001b[39m\u001b[92m+ OpenMDAOCore v0.3.3\u001b[39m\n",
      "  \u001b[90m[6099a3de] \u001b[39m\u001b[92m+ PythonCall v0.9.36\u001b[39m\n",
      "  \u001b[90m[37e2e46d] \u001b[39m\u001b[93m~ LinearAlgebra ⇒ v1.13.0\u001b[39m\n",
      "  \u001b[90m[458c3c95] \u001b[39m\u001b[93m~ OpenSSL_jll ⇒ v3.5.6+0\u001b[39m\n",
      "\u001b[32m\u001b[1m    Updating\u001b[22m\u001b[39m `~/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/julia_env/Manifest.toml`\n",
      "  \u001b[90m[47edcb42] \u001b[39m\u001b[92m+ ADTypes v1.24.0\u001b[39m\n",
      "  \u001b[90m[79e6a3ab] \u001b[39m\u001b[92m+ Adapt v4.7.1\u001b[39m\n",
      "  \u001b[90m[4fba245c] \u001b[39m\u001b[92m+ ArrayInterface v7.30.2\u001b[39m\n",
      "  \u001b[90m[d360d2e6] \u001b[39m\u001b[92m+ ChainRulesCore v1.26.1\u001b[39m\n",
      "  \u001b[90m[bbf7d656] \u001b[39m\u001b[92m+ CommonSubexpressions v0.3.1\u001b[39m\n",
      "  \u001b[90m[f70d9fcc] \u001b[39m\u001b[92m+ CommonWorldInvalidations v1.2.2\u001b[39m\n",
      "  \u001b[90m[34da2185] \u001b[39m\u001b[92m+ Compat v4.18.1\u001b[39m\n",
      "  \u001b[90m[b0b7db55] \u001b[39m\u001b[92m+ ComponentArrays v0.15.50\u001b[39m\n",
      "  \u001b[90m[992eb4ea] \u001b[39m\u001b[92m+ CondaPkg v0.2.36\u001b[39m\n",
      "  \u001b[90m[187b0558] \u001b[39m\u001b[92m+ ConstructionBase v1.6.0\u001b[39m\n",
      "  \u001b[90m[9a962f9c] \u001b[39m\u001b[92m+ DataAPI v1.16.0\u001b[39m\n",
      "\u001b[33m⌅\u001b[39m \u001b[90m[864edb3b] \u001b[39m\u001b[92m+ DataStructures v0.18.22\u001b[39m\n",
      "  \u001b[90m[e2d170a0] \u001b[39m\u001b[92m+ DataValueInterfaces v1.0.0\u001b[39m\n",
      "  \u001b[90m[163ba53b] \u001b[39m\u001b[92m+ DiffResults v1.1.0\u001b[39m\n",
      "  \u001b[90m[b552c78f] \u001b[39m\u001b[92m+ DiffRules v1.16.0\u001b[39m\n",
      "  \u001b[90m[a0c0ee7d] \u001b[39m\u001b[92m+ DifferentiationInterface v0.7.21\u001b[39m\n",
      "  \u001b[90m[ffbed154] \u001b[39m\u001b[92m+ DocStringExtensions v0.9.5\u001b[39m\n",
      "  \u001b[90m[f6369f11] \u001b[39m\u001b[92m+ ForwardDiff v1.4.6\u001b[39m\n",
      "  \u001b[90m[d9f16b24] \u001b[39m\u001b[92m+ Functors v0.5.3\u001b[39m\n",
      "  \u001b[90m[615f187c] \u001b[39m\u001b[92m+ IfElse v0.1.1\u001b[39m\n",
      "  \u001b[90m[92d709cd] \u001b[39m\u001b[92m+ IrrationalConstants v0.2.6\u001b[39m\n",
      "  \u001b[90m[82899510] \u001b[39m\u001b[92m+ IteratorInterfaceExtensions v1.0.0\u001b[39m\n",
      "  \u001b[90m[692b3bcd] \u001b[39m\u001b[92m+ JLLWrappers v1.8.0\u001b[39m\n",
      "  \u001b[90m[682c06a0] \u001b[39m\u001b[92m+ JSON v1.10.0\u001b[39m\n",
      "  \u001b[90m[2ab3a3ac] \u001b[39m\u001b[92m+ LogExpFunctions v1.0.2\u001b[39m\n",
      "  \u001b[90m[1914dd2f] \u001b[39m\u001b[92m+ MacroTools v0.5.16\u001b[39m\n",
      "  \u001b[90m[0b3b1443] \u001b[39m\u001b[92m+ MicroMamba v0.1.15\u001b[39m\n",
      "  \u001b[90m[a013c6e3] \u001b[39m\u001b[92m+ MyParaboloidPackage v0.1.0 `~/work/OpenMDAO/OpenMDAO/openmdao/docs/_executed_book/features/experimental/MyParaboloidPackage`\u001b[39m\n",
      "  \u001b[90m[77ba4419] \u001b[39m\u001b[92m+ NaNMath v1.1.4\u001b[39m\n",
      "  \u001b[90m[24d19c10] \u001b[39m\u001b[92m+ OpenMDAOCore v0.3.3\u001b[39m\n",
      "\u001b[33m⌅\u001b[39m \u001b[90m[bac558e1] \u001b[39m\u001b[92m+ OrderedCollections v1.8.2\u001b[39m\n",
      "  \u001b[90m[69de0a69] \u001b[39m\u001b[92m+ Parsers v3.0.0\u001b[39m\n",
      "  \u001b[90m[fa939f87] \u001b[39m\u001b[92m+ Pidfile v1.3.0\u001b[39m\n",
      "  \u001b[90m[aea7be01] \u001b[39m\u001b[92m+ PrecompileTools v1.3.4\u001b[39m\n",
      "  \u001b[90m[21216c6a] \u001b[39m\u001b[92m+ Preferences v1.6.0\u001b[39m\n",
      "  \u001b[90m[6099a3de] \u001b[39m\u001b[92m+ PythonCall v0.9.36\u001b[39m\n",
      "  \u001b[90m[431bcebd] \u001b[39m\u001b[92m+ SciMLPublic v1.3.0\u001b[39m\n",
      "  \u001b[90m[6c6a2e73] \u001b[39m\u001b[92m+ Scratch v1.3.0\u001b[39m\n",
      "  \u001b[90m[0a514795] \u001b[39m\u001b[92m+ SparseMatrixColorings v0.4.28\u001b[39m\n",
      "  \u001b[90m[276daf66] \u001b[39m\u001b[92m+ SpecialFunctions v2.9.0\u001b[39m\n",
      "  \u001b[90m[aedffcd0] \u001b[39m\u001b[92m+ Static v1.4.6\u001b[39m\n",
      "  \u001b[90m[0d7ed370] \u001b[39m\u001b[92m+ StaticArrayInterface v1.10.0\u001b[39m\n",
      "  \u001b[90m[1e83bf80] \u001b[39m\u001b[92m+ StaticArraysCore v1.4.4\u001b[39m\n",
      "  \u001b[90m[ec057cc2] \u001b[39m\u001b[92m+ StructUtils v2.9.2\u001b[39m\n",
      "  \u001b[90m[3783bdb8] \u001b[39m\u001b[92m+ TableTraits v1.0.1\u001b[39m\n",
      "  \u001b[90m[bd369af6] \u001b[39m\u001b[92m+ Tables v1.14.0\u001b[39m\n",
      "  \u001b[90m[1986cc42] \u001b[39m\u001b[92m+ Unitful v1.29.0\u001b[39m\n",
      "  \u001b[90m[6fb2a4bd] \u001b[39m\u001b[92m+ UnitfulAngles v0.7.2\u001b[39m\n",
      "  \u001b[90m[e17b2a0c] \u001b[39m\u001b[92m+ UnsafePointers v1.0.0\u001b[39m\n",
      "  \u001b[90m[efe28fd5] \u001b[39m\u001b[92m+ OpenSpecFun_jll v0.5.6+0\u001b[39m\n",
      "  \u001b[90m[f8abcde7] \u001b[39m\u001b[92m+ micromamba_jll v2.3.1+0\u001b[39m\n",
      "  \u001b[90m[4d7b5844] \u001b[39m\u001b[92m+ pixi_jll v0.76.2+0\u001b[39m\n",
      "  \u001b[90m[0dad84c5] \u001b[39m\u001b[92m+ ArgTools v1.1.2\u001b[39m\n",
      "  \u001b[90m[56f22d72] \u001b[39m\u001b[92m+ Artifacts v1.11.0\u001b[39m\n",
      "  \u001b[90m[2a0f44e3] \u001b[39m\u001b[92m+ Base64 v1.11.0\u001b[39m\n",
      "  \u001b[90m[ade2ca70] \u001b[39m\u001b[92m+ Dates v1.11.0\u001b[39m\n",
      "  \u001b[90m[f43a241f] \u001b[39m\u001b[92m+ Downloads v1.7.0\u001b[39m\n",
      "  \u001b[90m[7b1f6079] \u001b[39m\u001b[92m+ FileWatching v1.11.0\u001b[39m\n",
      "  \u001b[90m[b77e0a4c] \u001b[39m\u001b[92m+ InteractiveUtils v1.11.0\u001b[39m\n",
      "  \u001b[90m[ac6e5ff7] \u001b[39m\u001b[92m+ JuliaSyntaxHighlighting v1.12.0\u001b[39m\n",
      "  \u001b[90m[4af54fe1] \u001b[39m\u001b[92m+ LazyArtifacts v1.11.0\u001b[39m\n",
      "  \u001b[90m[b27032c2] \u001b[39m\u001b[92m+ LibCURL v1.0.0\u001b[39m\n",
      "  \u001b[90m[76f85450] \u001b[39m\u001b[92m+ LibGit2 v1.11.0\u001b[39m\n",
      "  \u001b[90m[8f399da3] \u001b[39m\u001b[92m+ Libdl v1.11.0\u001b[39m\n",
      "  \u001b[90m[37e2e46d] \u001b[39m\u001b[93m~ LinearAlgebra ⇒ v1.13.0\u001b[39m\n",
      "  \u001b[90m[56ddb016] \u001b[39m\u001b[92m+ Logging v1.11.0\u001b[39m\n",
      "  \u001b[90m[d6f4376e] \u001b[39m\u001b[92m+ Markdown v1.11.0\u001b[39m\n",
      "  \u001b[90m[ca575930] \u001b[39m\u001b[92m+ NetworkOptions v1.3.0\u001b[39m\n",
      "  \u001b[90m[44cfe95a] \u001b[39m\u001b[92m+ Pkg v1.13.0\u001b[39m\n",
      "  \u001b[90m[de0858da] \u001b[39m\u001b[92m+ Printf v1.11.0\u001b[39m\n",
      "  \u001b[90m[9a3f8284] \u001b[39m\u001b[92m+ Random v1.11.0\u001b[39m\n",
      "  \u001b[90m[ea8e919c] \u001b[39m\u001b[92m+ SHA v1.0.0\u001b[39m\n",
      "  \u001b[90m[9e88b42a] \u001b[39m\u001b[92m+ Serialization v1.11.0\u001b[39m\n",
      "  \u001b[90m[2f01184e] \u001b[39m\u001b[92m+ SparseArrays v1.13.0\u001b[39m\n",
      "  \u001b[90m[f489334b] \u001b[39m\u001b[92m+ StyledStrings v1.11.0\u001b[39m\n",
      "  \u001b[90m[fa267f1f] \u001b[39m\u001b[92m+ TOML v1.0.3\u001b[39m\n",
      "  \u001b[90m[a4e569a6] \u001b[39m\u001b[92m+ Tar v1.10.0\u001b[39m\n",
      "  \u001b[90m[8dfed614] \u001b[39m\u001b[92m+ Test v1.11.0\u001b[39m\n",
      "  \u001b[90m[cf7118a7] \u001b[39m\u001b[92m+ UUIDs v1.11.0\u001b[39m\n",
      "  \u001b[90m[4ec0a83e] \u001b[39m\u001b[92m+ Unicode v1.11.0\u001b[39m\n",
      "  \u001b[90m[e66e0078] \u001b[39m\u001b[92m+ CompilerSupportLibraries_jll v1.5.5+2\u001b[39m\n",
      "  \u001b[90m[deac9b47] \u001b[39m\u001b[92m+ LibCURL_jll v8.18.0+1\u001b[39m\n",
      "  \u001b[90m[e37daf67] \u001b[39m\u001b[92m+ LibGit2_jll v1.9.1+0\u001b[39m\n",
      "  \u001b[90m[29816b5a] \u001b[39m\u001b[92m+ LibSSH2_jll v1.11.104+0\u001b[39m\n",
      "  \u001b[90m[14a3606d] \u001b[39m\u001b[92m+ MozillaCACerts_jll v2026.8.13\u001b[39m\n",
      "  \u001b[90m[4536629a] \u001b[39m\u001b[92m+ OpenBLAS_jll v0.3.30+0\u001b[39m\n",
      "  \u001b[90m[05823500] \u001b[39m\u001b[92m+ OpenLibm_jll v0.8.7+0\u001b[39m\n",
      "  \u001b[90m[458c3c95] \u001b[39m\u001b[93m~ OpenSSL_jll ⇒ v3.5.6+0\u001b[39m\n",
      "  \u001b[90m[efcefdf7] \u001b[39m\u001b[92m+ PCRE2_jll v10.46.0+0\u001b[39m\n",
      "  \u001b[90m[bea87d4a] \u001b[39m\u001b[92m+ SuiteSparse_jll v7.10.1+0\u001b[39m\n",
      "  \u001b[90m[83775a58] \u001b[39m\u001b[92m+ Zlib_jll v1.3.1+2\u001b[39m\n",
      "  \u001b[90m[3161d3a3] \u001b[39m\u001b[92m+ Zstd_jll v1.5.7+1\u001b[39m\n",
      "  \u001b[90m[8e850b90] \u001b[39m\u001b[92m+ libblastrampoline_jll v5.15.0+0\u001b[39m\n",
      "  \u001b[90m[8e850ede] \u001b[39m\u001b[92m+ nghttp2_jll v1.67.1+0\u001b[39m\n",
      "  \u001b[90m[3f19e933] \u001b[39m\u001b[92m+ p7zip_jll v17.8.2+0\u001b[39m\n",
      "\u001b[36m\u001b[1m        Info\u001b[22m\u001b[39m Packages marked with \u001b[33m⌅\u001b[39m have new versions available but compatibility constraints restrict them from upgrading. To see why use `status --outdated -m`\n",
      "\u001b[36m\u001b[1m     Project\u001b[22m\u001b[39m No packages added to or removed from `~/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/julia_env/Project.toml`\n",
      "\u001b[36m\u001b[1m    Manifest\u001b[22m\u001b[39m No packages added to or removed from `~/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/julia_env/Manifest.toml`\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[36m\u001b[1m     Project\u001b[22m\u001b[39m No packages added to or removed from `~/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/julia_env/Project.toml`\n",
      "\u001b[36m\u001b[1m    Manifest\u001b[22m\u001b[39m No packages added to or removed from `~/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/julia_env/Manifest.toml`\n",
      "\u001b[32m\u001b[1mPrecompiling\u001b[22m\u001b[39m packages...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   0.7 s\u001b[32m  ✓ \u001b[39m\u001b[90mDataAPI\u001b[39m\n",
      "   0.8 s\u001b[32m  ✓ \u001b[39m\u001b[90mAdapt\u001b[39m\n",
      "   0.9 s\u001b[32m  ✓ \u001b[39m\u001b[90mConstructionBase\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   0.7 s\u001b[32m  ✓ \u001b[39m\u001b[90mDataValueInterfaces\u001b[39m\n",
      "   0.9 s\u001b[32m  ✓ \u001b[39m\u001b[90mUnsafePointers\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.7 s\u001b[32m  ✓ \u001b[39m\u001b[90mIrrationalConstants\u001b[39m\n",
      "   0.9 s\u001b[32m  ✓ \u001b[39m\u001b[90mStaticArraysCore\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   0.4 s\u001b[32m  ✓ \u001b[39m\u001b[90mIfElse\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   0.5 s\u001b[32m  ✓ \u001b[39m\u001b[90mIteratorInterfaceExtensions\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   0.9 s\u001b[32m  ✓ \u001b[39m\u001b[90mDocStringExtensions\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.4 s\u001b[32m  ✓ \u001b[39m\u001b[90mOrderedCollections\u001b[39m\n",
      "   0.9 s\u001b[32m  ✓ \u001b[39m\u001b[90mNaNMath\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   3.6 s\u001b[32m  ✓ \u001b[39m\u001b[90mMacroTools\u001b[39m\n",
      "   1.3 s\u001b[32m  ✓ \u001b[39m\u001b[90mScratch\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.0 s\u001b[32m  ✓ \u001b[39m\u001b[90mCompat\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.7 s\u001b[32m  ✓ \u001b[39m\u001b[90mStructUtils\u001b[39m\n",
      "   0.8 s\u001b[32m  ✓ \u001b[39m\u001b[90mPreferences\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.1 s\u001b[32m  ✓ \u001b[39m\u001b[90mPidfile\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   0.9 s\u001b[32m  ✓ \u001b[39m\u001b[90mConstructionBase → ConstructionBaseLinearAlgebraExt\u001b[39m\n",
      "   1.2 s\u001b[32m  ✓ \u001b[39m\u001b[90mArrayInterface\u001b[39m\n",
      "   1.0 s\u001b[32m  ✓ \u001b[39m\u001b[90mAdapt → AdaptSparseArraysExt\u001b[39m\n",
      "   0.7 s\u001b[32m  ✓ \u001b[39m\u001b[90mDiffResults\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   0.5 s\u001b[32m  ✓ \u001b[39m\u001b[90mCompat → CompatLinearAlgebraExt\u001b[39m\n",
      "   0.6 s\u001b[32m  ✓ \u001b[39m\u001b[90mTableTraits\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   0.7 s\u001b[32m  ✓ \u001b[39m\u001b[90mCommonSubexpressions\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.1 s\u001b[32m  ✓ \u001b[39m\u001b[90mLogExpFunctions\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.0 s\u001b[32m  ✓ \u001b[39m\u001b[90mStructUtils → StructUtilsStaticArraysCoreExt\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.1 s\u001b[32m  ✓ \u001b[39m\u001b[90mPrecompileTools\u001b[39m\n",
      "   0.8 s\u001b[32m  ✓ \u001b[39m\u001b[90mArrayInterface → ArrayInterfaceStaticArraysCoreExt\u001b[39m\n",
      "   1.3 s\u001b[32m  ✓ \u001b[39m\u001b[90mJLLWrappers\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   0.8 s\u001b[32m  ✓ \u001b[39m\u001b[90mFunctors\u001b[39m\n",
      "   1.2 s\u001b[32m  ✓ \u001b[39m\u001b[90mArrayInterface → ArrayInterfaceSparseArraysExt\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   2.4 s\u001b[32m  ✓ \u001b[39m\u001b[90mChainRulesCore\u001b[39m\n",
      "   1.5 s\u001b[32m  ✓ \u001b[39m\u001b[90mSciMLPublic\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.7 s\u001b[32m  ✓ \u001b[39m\u001b[90mTables\u001b[39m\n",
      "   2.7 s\u001b[32m  ✓ \u001b[39m\u001b[90mDataStructures\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.0 s\u001b[32m  ✓ \u001b[39m\u001b[90mCommonWorldInvalidations\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   2.2 s\u001b[32m  ✓ \u001b[39m\u001b[90mADTypes\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   2.1 s\u001b[32m  ✓ \u001b[39m\u001b[90mpixi_jll\u001b[39m\n",
      "   2.7 s\u001b[32m  ✓ \u001b[39m\u001b[90mmicromamba_jll\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.3 s\u001b[32m  ✓ \u001b[39m\u001b[90mOpenSpecFun_jll\u001b[39m\n",
      "   0.7 s\u001b[32m  ✓ \u001b[39m\u001b[90mArrayInterface → ArrayInterfaceChainRulesCoreExt\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.2 s\u001b[32m  ✓ \u001b[39m\u001b[90mChainRulesCore → ChainRulesCoreSparseArraysExt\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   0.8 s\u001b[32m  ✓ \u001b[39m\u001b[90mStructUtils → StructUtilsTablesExt\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.5 s\u001b[32m  ✓ \u001b[39m\u001b[90mLogExpFunctions → LogExpFunctionsChainRulesCoreExt\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.0 s\u001b[32m  ✓ \u001b[39m\u001b[90mADTypes → ADTypesConstructionBaseExt\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   2.1 s\u001b[32m  ✓ \u001b[39m\u001b[90mDifferentiationInterface\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.1 s\u001b[32m  ✓ \u001b[39m\u001b[90mADTypes → ADTypesChainRulesCoreExt\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m\u001b[1m Downloading\u001b[22m\u001b[39m artifact: micromamba\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   3.2 s\u001b[32m  ✓ \u001b[39m\u001b[90mMicroMamba\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   4.8 s\u001b[32m  ✓ \u001b[39m\u001b[90mSpecialFunctions\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.5 s\u001b[32m  ✓ \u001b[39m\u001b[90mDifferentiationInterface → DifferentiationInterfaceSparseArraysExt\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.1 s\u001b[32m  ✓ \u001b[39m\u001b[90mDifferentiationInterface → DifferentiationInterfaceChainRulesCoreExt\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "  15.1 s\u001b[32m  ✓ \u001b[39m\u001b[90mSparseMatrixColorings\u001b[39m\n",
      "   4.1 s\u001b[32m  ✓ \u001b[39m\u001b[90mSpecialFunctions → SpecialFunctionsChainRulesCoreExt\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.6 s\u001b[32m  ✓ \u001b[39m\u001b[90mDiffRules\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   2.3 s\u001b[32m  ✓ \u001b[39m\u001b[90mDifferentiationInterface → DifferentiationInterfaceSparseMatrixColoringsExt\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "  34.4 s\u001b[32m  ✓ \u001b[39m\u001b[90mUnitful\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "  24.4 s\u001b[32m  ✓ \u001b[39m\u001b[90mStatic\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.2 s\u001b[32m  ✓ \u001b[39m\u001b[90mUnitful → ConstructionBaseUnitfulExt\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.5 s\u001b[32m  ✓ \u001b[39m\u001b[90mUnitful → PrintfExt\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.5 s\u001b[32m  ✓ \u001b[39m\u001b[90mUnitful → NaNMathExt\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   7.1 s\u001b[32m  ✓ \u001b[39m\u001b[90mForwardDiff\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.5 s\u001b[32m  ✓ \u001b[39m\u001b[90mDifferentiationInterface → DifferentiationInterfaceForwardDiffExt\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   3.0 s\u001b[32m  ✓ \u001b[39m\u001b[90mUnitfulAngles\u001b[39m\n",
      "   1.8 s\u001b[32m  ✓ \u001b[39m\u001b[90mUnitful → ForwardDiffExt\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   4.3 s\u001b[32m  ✓ \u001b[39m\u001b[90mStaticArrayInterface\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.8 s\u001b[32m  ✓ \u001b[39m\u001b[90mComponentArrays\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.9 s\u001b[32m  ✓ \u001b[39mOpenMDAOCore\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   1.7 s\u001b[32m  ✓ \u001b[39mMyParaboloidPackage\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "  40.9 s\u001b[32m  ✓ \u001b[39m\u001b[90mParsers\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   8.7 s\u001b[32m  ✓ \u001b[39m\u001b[90mJSON\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m\u001b[1m Downloading\u001b[22m\u001b[39m artifact: pixi\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "   2.9 s\u001b[32m  ✓ \u001b[39m\u001b[90mCondaPkg\u001b[39m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "  13.5 s\u001b[32m  ✓ \u001b[39mPythonCall\n",
      "  73 dependencies successfully precompiled in 76 seconds. 35 already precompiled.\n",
      "\n",
      "  \u001b[33m2\u001b[39m dependencies had output during precompilation:\u001b[33m\n",
      "┌ \u001b[39mCondaPkg\u001b[33m\n",
      "│  \u001b[39m\u001b[32m\u001b[1m Downloading\u001b[22m\u001b[39m artifact: pixi\u001b[33m\n",
      "└  \u001b[39m\u001b[33m\n",
      "┌ \u001b[39mMicroMamba\u001b[33m\n",
      "│  \u001b[39m\u001b[32m\u001b[1m Downloading\u001b[22m\u001b[39m artifact: micromamba\u001b[33m\n",
      "└  \u001b[39m\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Detected IPython. Loading juliacall extension. See https://juliapy.github.io/PythonCall.jl/stable/compat/#IPython\n"
     ]
    }
   ],
   "source": [
    "import omjlcomps\n",
    "from paraboloid import get_paraboloid_comp\n",
    "jlcomp = get_paraboloid_comp()\n",
    "comp = omjlcomps.JuliaExplicitComp(jlcomp=jlcomp)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fb509b63",
   "metadata": {
    "papermill": {
     "duration": 0.002621,
     "end_time": "2026-10-02T14:46:31.944088+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:46:31.941467+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "Now we have a OpenMDAO `Component` that we can use.\n",
    "Let's try it out, following the [Paraboloid example](../../basic_user_guide/single_disciplinary_optimization/first_analysis) from the OpenMDAO docs:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "8f852cdd",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:46:31.950403Z",
     "iopub.status.busy": "2026-10-02T14:46:31.949996Z",
     "iopub.status.idle": "2026-10-02T14:46:35.952708Z",
     "shell.execute_reply": "2026-10-02T14:46:35.951933Z"
    },
    "papermill": {
     "duration": 4.006604,
     "end_time": "2026-10-02T14:46:35.953222+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:46:31.946618+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[runnervm8df0l:09273] pml_ucx.c:313  Error: Failed to create UCP worker\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-15.0\n",
      "-5.0\n",
      "[1790952393.142998] [runnervm8df0l:9273 :0]        ib_iface.c:1269 UCX  ERROR mana_0: iface 0x55a653753bd0 failed to create UD QP TX wr:256 sge:6 inl:64 resp:0 RX wr:4096 sge:1 resp:0 failed: Operation not supported\n",
      "[1790952393.143246] [runnervm8df0l:9273 :0]      ucp_worker.c:1412 UCX  ERROR uct_iface_open(ud_verbs/mana_0:1) failed: Input/output error\n"
     ]
    }
   ],
   "source": [
    "import openmdao.api as om\n",
    "\n",
    "model = om.Group()\n",
    "model.add_subsystem('parab_comp', comp)\n",
    "\n",
    "prob = om.Problem(model)\n",
    "\n",
    "prob.model.add_design_var(\"parab_comp.x\")\n",
    "prob.model.add_design_var(\"parab_comp.y\")\n",
    "prob.model.add_objective(\"parab_comp.f_xy\")\n",
    "\n",
    "prob.driver = om.ScipyOptimizeDriver()\n",
    "prob.driver.options[\"optimizer\"] = \"SLSQP\"\n",
    "\n",
    "prob.setup(force_alloc_complex=True)\n",
    "\n",
    "prob.set_val(\"parab_comp.x\", 3.0)\n",
    "prob.set_val(\"parab_comp.y\", -4.0)\n",
    "\n",
    "prob.run_model()\n",
    "print(prob[\"parab_comp.f_xy\"])  # Should print `[-15.]`\n",
    "\n",
    "prob.set_val(\"parab_comp.x\", 5.0)\n",
    "prob.set_val(\"parab_comp.y\", -2.0)\n",
    "\n",
    "prob.run_model()\n",
    "print(prob.get_val(\"parab_comp.f_xy\"))  # Should print `[-5.]`"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "00d07f85",
   "metadata": {
    "papermill": {
     "duration": 0.0027,
     "end_time": "2026-10-02T14:46:35.958951+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:46:35.956251+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "Looks good so far.\n",
    "A few things to note:\n",
    "* We added the `JuliaExplicitComp` to the `Group` in the normal way.\n",
    "* The variable names exposed to OpenMDAO match what was used in the input and output `ComponentVector`s passed to the `DenseADExplicitComp` constructor.\n",
    "* `prob.set_val` and `prob.get_val` worked just like usual.\n",
    "\n",
    "We can also check our derivatives using the usual OpenMDAO methods. We can do that with the finite difference method:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "6587e79b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:46:35.964917Z",
     "iopub.status.busy": "2026-10-02T14:46:35.964759Z",
     "iopub.status.idle": "2026-10-02T14:46:36.994084Z",
     "shell.execute_reply": "2026-10-02T14:46:36.993547Z"
    },
    "papermill": {
     "duration": 1.033011,
     "end_time": "2026-10-02T14:46:36.994558+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:46:35.961547+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">------------------------------------------------------------------------------\n",
       "Component: JuliaExplicitComp '<span style=\"color: #00ffff; text-decoration-color: #00ffff; font-weight: bold\">parab_comp</span>'\n",
       "------------------------------------------------------------------------------\n",
       "\n",
       "  <span style=\"color: #00ffff; text-decoration-color: #00ffff; font-weight: bold\">parab_comp</span>: <span style=\"color: #00ff00; text-decoration-color: #00ff00; font-weight: bold\">'f_xy'</span> wrt <span style=\"color: #00ff00; text-decoration-color: #00ff00; font-weight: bold\">'x'</span>\n",
       "\n",
       "    Max Tolerance Violation (Jfwd - Jfd) - (atol + rtol * Jfd) : (-9.996325e-07)\n",
       "      abs error: 1.000368e-06\n",
       "      rel error: 5.001840e-07\n",
       "      fwd value @ max viol: 2.000000e+00\n",
       "      fd value @ max viol: 2.000001e+00 (fd:forward)\n",
       "\n",
       "    Raw Forward Derivative (Jfwd)\n",
       "    [[ 2.000000000000e+00]]\n",
       "\n",
       "    Raw FD Derivative (Jfd)\n",
       "    [[ 2.000001000368e+00]]\n",
       "\n",
       " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
       "\n",
       "  <span style=\"color: #00ffff; text-decoration-color: #00ffff; font-weight: bold\">parab_comp</span>: <span style=\"color: #00ff00; text-decoration-color: #00ff00; font-weight: bold\">'f_xy'</span> wrt <span style=\"color: #00ff00; text-decoration-color: #00ff00; font-weight: bold\">'y'</span>\n",
       "\n",
       "    Max Tolerance Violation (Jfwd - Jfd) - (atol + rtol * Jfd) : (-7.999542e-06)\n",
       "      abs error: 1.000459e-06\n",
       "      rel error: 1.111621e-07\n",
       "      fwd value @ max viol: 9.000000e+00\n",
       "      fd value @ max viol: 9.000001e+00 (fd:forward)\n",
       "\n",
       "    Raw Forward Derivative (Jfwd)\n",
       "    [[ 9.000000000000e+00]]\n",
       "\n",
       "    Raw FD Derivative (Jfd)\n",
       "    [[ 9.000001000459e+00]]\n",
       "\n",
       " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
       "\n",
       "</pre>\n"
      ],
      "text/plain": [
       "------------------------------------------------------------------------------\n",
       "Component: JuliaExplicitComp '\u001b[1;96mparab_comp\u001b[0m'\n",
       "------------------------------------------------------------------------------\n",
       "\n",
       "  \u001b[1;96mparab_comp\u001b[0m: \u001b[1;92m'f_xy'\u001b[0m wrt \u001b[1;92m'x'\u001b[0m\n",
       "\n",
       "    Max Tolerance Violation (Jfwd - Jfd) - (atol + rtol * Jfd) : (-9.996325e-07)\n",
       "      abs error: 1.000368e-06\n",
       "      rel error: 5.001840e-07\n",
       "      fwd value @ max viol: 2.000000e+00\n",
       "      fd value @ max viol: 2.000001e+00 (fd:forward)\n",
       "\n",
       "    Raw Forward Derivative (Jfwd)\n",
       "    [[ 2.000000000000e+00]]\n",
       "\n",
       "    Raw FD Derivative (Jfd)\n",
       "    [[ 2.000001000368e+00]]\n",
       "\n",
       " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
       "\n",
       "  \u001b[1;96mparab_comp\u001b[0m: \u001b[1;92m'f_xy'\u001b[0m wrt \u001b[1;92m'y'\u001b[0m\n",
       "\n",
       "    Max Tolerance Violation (Jfwd - Jfd) - (atol + rtol * Jfd) : (-7.999542e-06)\n",
       "      abs error: 1.000459e-06\n",
       "      rel error: 1.111621e-07\n",
       "      fwd value @ max viol: 9.000000e+00\n",
       "      fd value @ max viol: 9.000001e+00 (fd:forward)\n",
       "\n",
       "    Raw Forward Derivative (Jfwd)\n",
       "    [[ 9.000000000000e+00]]\n",
       "\n",
       "    Raw FD Derivative (Jfd)\n",
       "    [[ 9.000001000459e+00]]\n",
       "\n",
       " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
       "\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'parab_comp': {('f_xy', 'x'): {'J_fwd': array([[2.]]), 'J_fd': array([[2.000001]]), 'rows': None, 'cols': None, 'tol violation': _ErrorData(forward=-9.99632543852158e-07, reverse=None, fwd_rev=None), 'magnitude': _MagnitudeData(forward=2.0, reverse=0.0, fd=2.0000010003684565), 'vals_at_max_error': _ErrorData(forward=(np.float64(2.0), np.float64(2.0000010003684565)), reverse=None, fwd_rev=None), 'abs error': _ErrorData(forward=1.0003684565162985e-06, reverse=None, fwd_rev=None), 'rel error': _ErrorData(forward=5.001839780740122e-07, reverse=None, fwd_rev=None)}, ('f_xy', 'y'): {'J_fwd': array([[9.]]), 'J_fd': array([[9.000001]]), 'rows': None, 'cols': None, 'tol violation': _ErrorData(forward=-7.999542276593274e-06, reverse=None, fwd_rev=None), 'magnitude': _MagnitudeData(forward=9.0, reverse=0.0, fd=9.000001000458724), 'vals_at_max_error': _ErrorData(forward=(np.float64(9.0), np.float64(9.000001000458724)), reverse=None, fwd_rev=None), 'abs error': _ErrorData(forward=1.0004587238654494e-06, reverse=None, fwd_rev=None), 'rel error': _ErrorData(forward=1.1116206807248763e-07, reverse=None, fwd_rev=None)}}}\n"
     ]
    }
   ],
   "source": [
    "print(prob.check_partials(method=\"fd\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bc0ef72f",
   "metadata": {
    "papermill": {
     "duration": 0.00281,
     "end_time": "2026-10-02T14:46:37.000494+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:46:36.997684+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "Or we could use the complex-step method:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "ef8f24b4",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:46:37.006800Z",
     "iopub.status.busy": "2026-10-02T14:46:37.006611Z",
     "iopub.status.idle": "2026-10-02T14:46:37.462221Z",
     "shell.execute_reply": "2026-10-02T14:46:37.461592Z"
    },
    "papermill": {
     "duration": 0.459736,
     "end_time": "2026-10-02T14:46:37.462973+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:46:37.003237+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">------------------------------------------------------------------------------\n",
       "Component: JuliaExplicitComp '<span style=\"color: #00ffff; text-decoration-color: #00ffff; font-weight: bold\">parab_comp</span>'\n",
       "------------------------------------------------------------------------------\n",
       "\n",
       "  <span style=\"color: #00ffff; text-decoration-color: #00ffff; font-weight: bold\">parab_comp</span>: <span style=\"color: #00ff00; text-decoration-color: #00ff00; font-weight: bold\">'f_xy'</span> wrt <span style=\"color: #00ff00; text-decoration-color: #00ff00; font-weight: bold\">'x'</span>\n",
       "\n",
       "    Max Tolerance Violation (Jfwd - Jfd) - (atol + rtol * Jfd) : (-2.000000e-06)\n",
       "      abs error: 0.000000e+00\n",
       "      rel error: 0.000000e+00\n",
       "      fwd value @ max viol: 2.000000e+00\n",
       "      fd value @ max viol: 2.000000e+00 (cs:None)\n",
       "\n",
       "    Raw Forward Derivative (Jfwd)\n",
       "    [[ 2.000000000000e+00]]\n",
       "\n",
       "    Raw CS Derivative (Jfd)\n",
       "    [[ 2.000000000000e+00]]\n",
       "\n",
       " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
       "\n",
       "  <span style=\"color: #00ffff; text-decoration-color: #00ffff; font-weight: bold\">parab_comp</span>: <span style=\"color: #00ff00; text-decoration-color: #00ff00; font-weight: bold\">'f_xy'</span> wrt <span style=\"color: #00ff00; text-decoration-color: #00ff00; font-weight: bold\">'y'</span>\n",
       "\n",
       "    Max Tolerance Violation (Jfwd - Jfd) - (atol + rtol * Jfd) : (-9.000000e-06)\n",
       "      abs error: 0.000000e+00\n",
       "      rel error: 0.000000e+00\n",
       "      fwd value @ max viol: 9.000000e+00\n",
       "      fd value @ max viol: 9.000000e+00 (cs:None)\n",
       "\n",
       "    Raw Forward Derivative (Jfwd)\n",
       "    [[ 9.000000000000e+00]]\n",
       "\n",
       "    Raw CS Derivative (Jfd)\n",
       "    [[ 9.000000000000e+00]]\n",
       "\n",
       " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
       "\n",
       "</pre>\n"
      ],
      "text/plain": [
       "------------------------------------------------------------------------------\n",
       "Component: JuliaExplicitComp '\u001b[1;96mparab_comp\u001b[0m'\n",
       "------------------------------------------------------------------------------\n",
       "\n",
       "  \u001b[1;96mparab_comp\u001b[0m: \u001b[1;92m'f_xy'\u001b[0m wrt \u001b[1;92m'x'\u001b[0m\n",
       "\n",
       "    Max Tolerance Violation (Jfwd - Jfd) - (atol + rtol * Jfd) : (-2.000000e-06)\n",
       "      abs error: 0.000000e+00\n",
       "      rel error: 0.000000e+00\n",
       "      fwd value @ max viol: 2.000000e+00\n",
       "      fd value @ max viol: 2.000000e+00 (cs:None)\n",
       "\n",
       "    Raw Forward Derivative (Jfwd)\n",
       "    [[ 2.000000000000e+00]]\n",
       "\n",
       "    Raw CS Derivative (Jfd)\n",
       "    [[ 2.000000000000e+00]]\n",
       "\n",
       " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
       "\n",
       "  \u001b[1;96mparab_comp\u001b[0m: \u001b[1;92m'f_xy'\u001b[0m wrt \u001b[1;92m'y'\u001b[0m\n",
       "\n",
       "    Max Tolerance Violation (Jfwd - Jfd) - (atol + rtol * Jfd) : (-9.000000e-06)\n",
       "      abs error: 0.000000e+00\n",
       "      rel error: 0.000000e+00\n",
       "      fwd value @ max viol: 9.000000e+00\n",
       "      fd value @ max viol: 9.000000e+00 (cs:None)\n",
       "\n",
       "    Raw Forward Derivative (Jfwd)\n",
       "    [[ 9.000000000000e+00]]\n",
       "\n",
       "    Raw CS Derivative (Jfd)\n",
       "    [[ 9.000000000000e+00]]\n",
       "\n",
       " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
       "\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'parab_comp': {('f_xy', 'x'): {'J_fwd': array([[2.]]), 'J_fd': array([[2.]]), 'rows': None, 'cols': None, 'tol violation': _ErrorData(forward=-2e-06, reverse=None, fwd_rev=None), 'magnitude': _MagnitudeData(forward=2.0, reverse=0.0, fd=2.0), 'vals_at_max_error': _ErrorData(forward=(np.float64(2.0), np.float64(2.0)), reverse=None, fwd_rev=None), 'abs error': _ErrorData(forward=0.0, reverse=None, fwd_rev=None), 'rel error': _ErrorData(forward=0.0, reverse=None, fwd_rev=None)}, ('f_xy', 'y'): {'J_fwd': array([[9.]]), 'J_fd': array([[9.]]), 'rows': None, 'cols': None, 'tol violation': _ErrorData(forward=-9e-06, reverse=None, fwd_rev=None), 'magnitude': _MagnitudeData(forward=9.0, reverse=0.0, fd=9.0), 'vals_at_max_error': _ErrorData(forward=(np.float64(9.0), np.float64(9.0)), reverse=None, fwd_rev=None), 'abs error': _ErrorData(forward=0.0, reverse=None, fwd_rev=None), 'rel error': _ErrorData(forward=0.0, reverse=None, fwd_rev=None)}}}\n"
     ]
    }
   ],
   "source": [
    "print(prob.check_partials(method=\"cs\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0b788ab8",
   "metadata": {
    "papermill": {
     "duration": 0.004235,
     "end_time": "2026-10-02T14:46:37.472025+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:46:37.467790+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "The derivatives look great, so let's try an optimization:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "ea0369eb",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:46:37.480073Z",
     "iopub.status.busy": "2026-10-02T14:46:37.479905Z",
     "iopub.status.idle": "2026-10-02T14:46:37.512664Z",
     "shell.execute_reply": "2026-10-02T14:46:37.511978Z"
    },
    "papermill": {
     "duration": 0.036965,
     "end_time": "2026-10-02T14:46:37.513180+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:46:37.476215+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Optimization terminated successfully    (Exit mode 0)\n",
      "            Current function value: -27.333333333333336\n",
      "            Iterations: 4\n",
      "            Function evaluations: 5\n",
      "            Gradient evaluations: 4\n",
      "Optimization Complete\n",
      "-----------------------------------\n",
      "f_xy = -27.333333333333336\n",
      "x = 6.666666666666666\n",
      "y = -7.333333333333333\n"
     ]
    }
   ],
   "source": [
    "prob.run_driver()\n",
    "print(f\"f_xy = {prob.get_val('parab_comp.f_xy')}\")  # Should print `[-27.333333]`\n",
    "print(f\"x = {prob.get_val('parab_comp.x')}\")  # Should print `[6.666666]`\n",
    "print(f\"y = {prob.get_val('parab_comp.y')}\")  # Should print `[-7.333333]`"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "56f47330",
   "metadata": {
    "papermill": {
     "duration": 0.004223,
     "end_time": "2026-10-02T14:46:37.521965+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:46:37.517742+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "Victory!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "708db0bb",
   "metadata": {
    "papermill": {
     "duration": 0.054783,
     "end_time": "2026-10-02T14:46:37.581036+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:46:37.526253+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# Next Steps\n",
    "We've shown how to put together a simple OpenMDAO `Component` using Julia and OpenMDAO.jl.\n",
    "OpenMDAO.jl has more features that you can [explore in docs](https://flow.byu.edu/OpenMDAO.jl/dev/).\n",
    "Some things we haven't covered:\n",
    "* We didn't define any units or tags for our Paraboloid example, but OpenMDAO.jl does support those features. Check out the [Brachistochrone example](https://flow.byu.edu/OpenMDAO.jl/dev/auto_sparse_ad/#The-Brachistochrone-with-SparseADExplicitComp) to see how that is done.\n",
    "* OpenMDAO.jl also supports determining variable shapes at runtime (aka the `copy_shape` and `shape_by_conn` arguments to `add_input` and `add_output`). Currently an example of using those features doesn't exist for the various AD methods, but the [docstring for `DenseADExplicitComp` and friends](https://flow.byu.edu/OpenMDAO.jl/dev/reference/#OpenMDAOCore.DenseADExplicitComp-Union{Tuple{TAD},%20Tuple{TAD,%20Any,%20ComponentArrays.ComponentVector,%20ComponentArrays.ComponentVector}}%20where%20TAD%3C:ADTypes.AbstractADType) should show you how to do it. \n",
    "* We just used one AD package in the example above (ForwardDiff.jl), but there are many more. Check out the [ADTypes.jl documentation](https://docs.sciml.ai/ADTypes/stable/) for all the possible options.\n",
    "* We used the `DenseADExplicitComp` `struct` to create our Paraboloid component, which is the most appropriate for a component with a dense Jacobian. But OpenMDAO.jl can also create components that evaluate the derivatives using the [matrix-free approach](https://flow.byu.edu/OpenMDAO.jl/dev/matrix_free_ad/), or [accelerate the calculation of sparse Jacobians using coloring algorithms](https://flow.byu.edu/OpenMDAO.jl/dev/auto_sparse_ad/).\n",
    "* The OpenMDAO.jl docs also have [recommendations on how to create Python packages that contain Julia OpenMDAO components](https://flow.byu.edu/OpenMDAO.jl/dev/creating_python_packages/) that you should definitely check out if you plan on using OpenMDAO.jl for \"real work.\" There is also an example Python package that follows these guidelines in the GitHub repository.\n",
    "* In the aformentioned example Python package in the OpenMDAO.jl GitHub repository there is an example of using OpenMDAO.jl and [ImplicitAD.jl](https://github.com/byuflowlab/ImplicitAD.jl) to solve [the nonlinear circuit example from the OpenMDAO docs](../../advanced_user_guide/models_implicit_components/models_with_solvers_implicit). This shows how we can use OpenMDAO.jl to efficiently differentiate through an implicit calculation with a little help from ImplicitAD.jl."
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Tags",
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.14"
  },
  "orphan": true,
  "papermill": {
   "default_parameters": {},
   "duration": 98.926898,
   "end_time": "2026-10-02T14:46:38.304567+00:00",
   "environment_variables": {},
   "exception": null,
   "input_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/openmdao_book/features/experimental/julia_explicit_ad.ipynb",
   "output_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/_executed_book/features/experimental/julia_explicit_ad.ipynb",
   "parameters": {},
   "start_time": "2026-10-02T14:44:59.377669+00:00",
   "version": "2.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}