PK v[U='Du u dataframe.ipynb{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n# Create a discipline that uses pandas DataFrames\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from __future__ import annotations\n\nfrom gemseo.api import configure_logger\nfrom gemseo.core.discipline import MDODiscipline\nfrom numpy import ndarray\nfrom pandas import DataFrame" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Import\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "configure_logger()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create a discipline that uses a DataFrame\n\nWe will create a class for a simple discipline that computes an output\nvariable ``y = 1 - 0.2 * x`` where ``x`` is an input variable.\nFor whatever reason, the business logic of this discipline uses a pandas DataFrame\nto store the input and output values outside |g|.\nAlthough |g| disciplines only handle input and output variables that are NumPy arrays,\ntheir local data and default input values can use DataFrame objects.\n\nThe input and output grammars of the discipline shall use a naming convention\nto access the names of the columns of a DataFrame.\nThe naming convention is built with the name of the input or output,\nthe character ``~`` (this can be changed) and\nthe name of the DataFrame column.\n\nThe code executed by the discipline is in the ``_run`` method,\nwhere ``self.local_data``, i.e. the local data, has automatically been initialized\nwith the default inputs and updated with the inputs passed to the discipline.\nA DataFrame can be retrieved by querying the corresponding key, e.g. ``df``,\nin the local data and then changes can be made to this DataFrame, e.g.\n``discipline.local_data[\"df\"][\"x\"] = value``.\n\nThe default inputs and local data are instances of :class:`.DisciplineData`.\n\n.. seealso::\n\n :class:`.DisciplineData` has more information about how DataFrames are handled.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "class DataFrameDiscipline(MDODiscipline):\n def __init__(self):\n super().__init__(grammar_type=MDODiscipline.SIMPLE_GRAMMAR_TYPE)\n self.default_inputs = {\"df\": DataFrame(data={\"x\": [0.0]})}\n self.input_grammar.update({\"df~x\": ndarray})\n self.output_grammar.update({\"df~y\": ndarray})\n\n def _run(self):\n df = self.local_data[\"df\"]\n df[\"y\"] = 1.0 - 0.2 * df[\"x\"]\n\n # The code above could also have been written as\n # self.local_data[\"df~y\"] = 1.0 - 0.2 * self.local_data[\"df~x\"]\n # self.local_data[\"df\"][\"y\"] = 1.0 - 0.2 * self.local_data[\"df\"][\"x\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Instantiate the discipline\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "discipline = DataFrameDiscipline()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Execute the discipline\nThen, we can execute it easily, either considering default inputs:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "print(discipline.execute())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "or using new inputs:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "print(discipline.execute({\"df~x\": [1.0]}))" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.9.13" } }, "nbformat": 4, "nbformat_minor": 0 }PK v[U&Z plot_autopydiscipline.ipynb{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n# Create a discipline from a Python function\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Import\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from __future__ import annotations\n\nfrom gemseo.api import configure_logger\nfrom gemseo.api import create_discipline\nfrom numpy import array\nfrom numpy import empty\n\nconfigure_logger()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Build a discipline from a simple Python function\nLet's consider a simple Python function, e.g.:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def f(x=0.0, y=0.0):\n \"\"\"A simple Python function.\"\"\"\n z = x + 2 * y\n return z" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create and instantiate the discipline\nThen, we can consider the\n:class:`.AutoPyDiscipline` class\nto convert it into an :class:`.MDODiscipline`.\nFor that, we can use the :meth:`~gemseo.api.create_discipline` API function\nwith :code:`'AutoPyDiscipline'` as first argument:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "disc = create_discipline(\"AutoPyDiscipline\", py_func=f)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The original Python function may or may not include default values for input\narguments, however, if the resulting :class:`.AutoPyDiscipline` is going to be\nplaced inside an :class:`.MDF`, a :class:`.BiLevel` formulation or an :class:`.MDA`\nwith strong couplings, then the Python function **must** assign default values\nfor its input arguments.\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Execute the discipline\nThen, we can execute it easily, either considering default inputs:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "print(disc.execute())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "or using new inputs:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "print(disc.execute({\"x\": array([1.0]), \"y\": array([-3.2])}))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Optional arguments\nThe optional arguments passed to the constructor are:\n\n- :code:`py_jac=None`: pointer to the jacobian function which must returned\n a 2D numpy array (see below),\n- :code:`use_arrays=False`: if :code:`True`, the function is expected to take\n arrays as inputs and give outputs as arrays,\n- :code:`write_schema=False`: if :code:`True`, write the json schema on the\n disk.\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Define the jacobian function\nHere is an example of jacobian function:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def dfdxy(x=0.0, y=0.0):\n \"\"\"Jacobian function of f.\"\"\"\n jac = empty((2, 1))\n jac[0, 0] = 1\n jac[1, 0] = 2\n return jac" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "that we can execute with default inputs for example:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "print(dfdxy())" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.9.13" } }, "nbformat": 4, "nbformat_minor": 0 }PK v[U]5 5 plot_remapping_discipline.ipynb{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n# Rename the input and output variables\n\nThe :class:`.RemappingDiscipline` can be used\nto rename the input and output variables of an original discipline\nincluding defining a variable as a part of an original one.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from __future__ import annotations\n\nfrom gemseo.core.discipline import MDODiscipline\nfrom gemseo.disciplines.remapping import RemappingDiscipline\nfrom numpy import array" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let us consider a discipline that sums up the fruits of the market.\nThe fruits can be classified into three categories:\npears, Gala apples and Fuji apples.\nThen,\nthe input variable of the discipline called ``fruits`` is a triplet\ncontaining the numbers of pears, Gala apples and Fuji apples so ordered.\nConcerning the outputs,\n``n_fruits`` is the total number of fruits\nwhile ``n_fruits_per_category`` gathers the numbers of pears and apples so ordered.\nThis discipline can be coded as follows:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "class FruitCounting(MDODiscipline):\n def __init__(self) -> None:\n super().__init__()\n self.input_grammar.update([\"fruits\"])\n self.output_grammar.update([\"n_fruits\", \"n_fruits_per_category\"])\n self.default_inputs = {\"fruits\": array([1, 2, 3])}\n\n def _run(self) -> None:\n fruits = self.local_data[\"fruits\"]\n self.store_local_data(\n n_fruits=array([fruits.sum()]),\n n_fruits_per_category=array([fruits[0], fruits[1:3].sum()]),\n )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "and we can instantiate it:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fruit_counting = FruitCounting()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then,\nwe create a new discipline renaming ``fruits`` as ``pear`` and ``apples``\nand ``n_fruits`` and ``n_fruits_per_category`` as ``total`` and ``sub_total``\nto improve the naming:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "clearer_fruit_counting = RemappingDiscipline(\n fruit_counting,\n {\"pear\": (\"fruits\", 0), \"apples\": (\"fruits\", [1, 2])},\n {\"total\": \"n_fruits\", \"sub_total\": \"n_fruits_per_category\"},\n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note:\n :class:`.RemappingDiscipline` requires an instance of the original discipline,\n the input names mapping to the original input names\n and the outputs names mapping to the original output names.\n More precisely,\n an input or output name mapping looks like\n ``{\"new_x\": \"x\", \"new_y\": (\"y\", components)}``\n where the variable ``\"new_x\"`` corresponds to the original variable ``\"x\"``\n and the variable ``\"new_y\"`` corresponds to some ``components``\n of the original variable ``\"y\"``.\n ``components`` can be an integer ``i`` (the ``i``-th component of ``y``),\n a sequence of integers ``[i, j, k]``\n (the ``i``-th, ``j``-th and ``k``-th components of ``y``)\n or an iterable of integers ``range(i, j+1)``\n (from the ``i``-th to the ``j``-th components of ``y``).\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can execute this discipline with the original default input values,\nnamely 1 pear, 2 Gala apples and 3 Fuji apples:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "clearer_fruit_counting.execute()\nprint(clearer_fruit_counting.get_input_data())\nprint(clearer_fruit_counting.get_output_data())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "or with new input data:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "clearer_fruit_counting.execute({\"pear\": array([4]), \"apples\": array([3, 1])})\nprint(clearer_fruit_counting.get_input_data())\nprint(clearer_fruit_counting.get_output_data())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To be even more clear,\nwe can split ``apples`` into ``gala`` and ``fuji``\nand ``sub_total`` into ``n_pears`` and ``n_apples``:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "even_clearer_fruit_counting = RemappingDiscipline(\n clearer_fruit_counting,\n {\"pear\": \"pear\", \"gala\": (\"apples\", 0), \"fuji\": (\"apples\", 0)},\n {\n \"total\": \"total\",\n \"n_pears\": (\"sub_total\", 0),\n \"n_apples\": (\"sub_total\", 1),\n },\n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "and count the number of fruits:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "even_clearer_fruit_counting.execute(\n {\"pear\": array([4]), \"gala\": array([3]), \"fuji\": array([1])}\n)\nprint(even_clearer_fruit_counting.get_input_data())\nprint(even_clearer_fruit_counting.get_output_data())" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.9.13" } }, "nbformat": 4, "nbformat_minor": 0 }PK v[U plot_interface_exec.ipynb{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n# Create a discipline from an external executable\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from __future__ import annotations\n\nimport os\nimport subprocess\n\nfrom gemseo.api import configure_logger\nfrom gemseo.core.discipline import MDODiscipline\nfrom numpy import array\n\nconfigure_logger()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Introduction\n\nLet's consider a binary software computing the float output\n$c = a^2 + b^2$ from two float inputs : :code:`'a'` and :code:`'b'`.\n\nThe inputs are read in the :code:`'inputs.txt'` file\nwhich looks like: `a=1 b=2` and\nthe output is written to: :code:`'outputs.txt'` which looks like `c=5`.\n\nThen, the executable can be run using the shell command :code:`'python run.py'`.\nLet's make a discipline out of this from an initial :code:`'inputs.txt'`.\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Implementation of the discipline\n\nThe construction of :class:`.MDODiscipline` consists in three steps:\n\n1. Instantiate the :class:`.MDODiscipline` using the super constructor,\n2. Initialize the grammars using the\n :meth:`.JSONGrammar.update` method,\n3. Set the default inputs from the initial :code:`'inputs.txt'`\n\nThe :class:`!MDODiscipline._run` method consists in three steps:\n\n1. Get the input data from :attr:`!MDODiscipline.local_data` and write the\n :code:`'inputs.txt'` file,\n2. Run the executable using the :code:`subprocess.run()` command ([see more](https://docs.python.org/3/library/subprocess.html#subprocess.run)),\n3. Get the output values and store them to :attr:`!MDODiscipline.local_data`.\n\nNow you can implement the discipline in the following way:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def parse_file(file_path):\n data = {}\n with open(file_path) as inf:\n for line in inf.readlines():\n if len(line) == 0:\n continue\n name, value = line.replace(\"\\n\", \"\").split(\"=\")\n data[name] = array([float(value)])\n\n return data\n\n\ndef write_file(data, file_path):\n with open(file_path, \"w\") as outf:\n for name, value in list(data.items()):\n outf.write(name + \"=\" + str(value[0]) + \"\\n\")\n\n\nclass ShellExecutableDiscipline(MDODiscipline):\n def __init__(self):\n super().__init__(\"ShellDisc\")\n self.input_grammar.update([\"a\", \"b\"])\n self.output_grammar.update([\"c\"])\n self.default_inputs = {\"a\": array([1.0]), \"b\": array([2.0])}\n\n def _run(self):\n cwd = os.getcwd()\n inputs_file = os.path.join(cwd, \"inputs.txt\")\n outputs_file = os.path.join(cwd, \"outputs.txt\")\n write_file(self.local_data, inputs_file)\n subprocess.run(\"python run.py\".split(), cwd=cwd)\n outputs = parse_file(outputs_file)\n self.local_data.update(outputs)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Execution of the discipline\nNow we can run it with default input values:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "shell_disc = ShellExecutableDiscipline()\nprint(shell_disc.execute())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "or run it with new input values:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "print(shell_disc.execute({\"a\": array([2.0]), \"b\": array([3.0])}))" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.9.13" } }, "nbformat": 4, "nbformat_minor": 0 }PK v[UoJ plot_analyticdiscipline.ipynb{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n# Create a discipline from analytical expressions\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from __future__ import annotations\n\nfrom gemseo.api import configure_logger\nfrom gemseo.api import create_discipline\nfrom numpy import array" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Import\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "configure_logger()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Introduction\nA simple :class:`.MDODiscipline` can be created\nusing analytic formulas, e.g. $y_1=2x^2$ and $y_2=5+3x^2z^3$,\nthanks to the :class:`.AnalyticDiscipline` class\nwhich is a quick alternative to model a simple analytic MDO problem.\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create the dictionary of analytic outputs\nFirst of all, we have to define the output expressions in a dictionary\nwhere keys are output names and values are formula with :code:`string`\nformat:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "expressions = {\"y_1\": \"2*x**2\", \"y_2\": \"5+3*x**2+z**3\"}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create the discipline\nThen, we create and instantiate the corresponding\n:class:`.AnalyticDiscipline`,\nwhich is a particular :class:`.MDODiscipline`.\nFor that, we use the API function :meth:`~gemseo.api.create_discipline` with:\n\n- :code:`discipline_name=\"AnalyticDiscipline\"`,\n- :code:`name=\"analytic\"`,\n- :code:`expressions=expr_dict`.\n\nIn practice, we write:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "disc = create_discipline(\"AnalyticDiscipline\", expressions=expressions)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
|g| takes care of the grammars and\n :meth:`!MDODiscipline._run` method generation\n from the :code:`expressions` argument.\n In the background, |g| considers that :code:`x` is a monodimensional\n float input parameter and :code:`y_1` and :code:`y_2` are\n monodimensional float output parameters.