{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{(0, 1, 1, 2), (1, 0, 1, 2), (2, 0, 1, 1), (0, 2, 1, 1), (0, 1, 2, 1), (1, 2, 1, 0), (1, 1, 2, 0), (2, 1, 1, 0), (1, 0, 2, 1), (1, 2, 0, 1), (2, 1, 0, 1), (1, 1, 0, 2)}\n" ] } ], "source": [ "from itertools import permutations\n", "g = permutations((2,1,1,0))\n", "UNIQUE = {p for p in g} # set comprehension\n", "print(UNIQUE)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'/Users/mac/Documents/School_of_Tomorrow'" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import os\n", "\n", "os.chdir('/Users/mac/Documents/School_of_Tomorrow')\n", "os.getcwd()" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "from qrays import Qvector\n", "IVM_DIRS = {Qvector(x) for x in UNIQUE}" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{0: {ivm_vector(a=0, b=0, c=0, d=0)}}" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "IVM = {}\n", "IVM[0] = {Qvector((0,0,0,0))}\n", "IVM" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "import flextegrity\n", "import flex_scripts" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import imp\n", "imp.reload(flextegrity)\n", "imp.reload(flex_scripts)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "from flextegrity import Edge, pov_header, Cuboctahedron, Icosahedron, Struts, Cube, RD\n", "from flextegrity import twelve_around_one, draw_edge, draw_poly, draw_vert\n", "import flextegrity" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [], "source": [ "def add_layer():\n", " global IVM\n", " directions = [Qvector(u) for u in UNIQUE]\n", " maxlayer = max(IVM.keys())\n", " nextlayer = maxlayer + 1\n", " the_set = set()\n", " for idx, center in enumerate(IVM[maxlayer]):\n", " # print(idx)\n", " for v in directions:\n", " candidate = center + v\n", " # print(\"Checking\", candidate)\n", " if (candidate in IVM[maxlayer]):\n", " # print(candidate, \"no good\")\n", " continue\n", " if (maxlayer-1 in IVM) and (candidate in IVM[maxlayer-1]):\n", " # print(candidate, \"no good\")\n", " continue\n", " # print(candidate, \"OK!\")\n", " the_set.add(candidate)\n", " \n", " IVM[nextlayer] = the_set " ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [], "source": [ "add_layer()" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "252" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(IVM[5])" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [], "source": [ "edges = set()\n", "\n", "def check_in(v0, v1):\n", " candidate = tuple(sorted([v0, v1]))\n", " edges.add(candidate)\n", " \n", "def get_edges():\n", " for layer in IVM:\n", " for ball in IVM[layer]:\n", " for v in IVM_DIRS:\n", " other = ball + v\n", "\n", " if other in IVM[layer]:\n", " check_in(ball, other)\n", " continue\n", " \n", " if layer-1 in IVM:\n", " if other in IVM[layer - 1]:\n", " # check_in(ball, other)\n", " continue\n", " \n", " if layer+1 in IVM: \n", " if other in IVM[layer+1]:\n", " # check_in(ball, other) \n", " continue\n", " \n", "def make_edge_list():\n", " the_list = []\n", " for e in edges:\n", " the_list.append(Edge(*e))\n", " return the_list" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{0: {ivm_vector(a=0, b=0, c=0, d=0)},\n", " 1: {ivm_vector(a=0, b=1, c=1, d=2),\n", " ivm_vector(a=0, b=1, c=2, d=1),\n", " ivm_vector(a=0, b=2, c=1, d=1),\n", " ivm_vector(a=1, b=0, c=1, d=2),\n", " ivm_vector(a=1, b=0, c=2, d=1),\n", " ivm_vector(a=1, b=1, c=0, d=2),\n", " ivm_vector(a=1, b=1, c=2, d=0),\n", " ivm_vector(a=1, b=2, c=0, d=1),\n", " ivm_vector(a=1, b=2, c=1, d=0),\n", " ivm_vector(a=2, b=0, c=1, d=1),\n", " ivm_vector(a=2, b=1, c=0, d=1),\n", " ivm_vector(a=2, b=1, c=1, d=0)}}" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "IVM" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "with open(\"ivm_test.pov\", \"w\") as target:\n", " c = \"rgb <0, 0, 1>\"\n", " target.write(pov_header)\n", " for e in make_edge_list():\n", " draw_edge(e, c, 0.03, target)" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [], "source": [ "edges = set()" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [], "source": [ "get_edges()" ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1320" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(edges)" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dict_keys([0, 1])" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "IVM.keys()" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "import math\n", "PHI = (1 + math.sqrt(5))/2.0\n", "flextegrity.IVM = IVM\n", "\n", "with open(\"flextegrity5.pov\", \"w\") as target:\n", " target.write(pov_header) \n", " c = Cube()\n", " ico = Icosahedron() * (1/PHI * math.sqrt(2)/2)\n", " st = Struts(c, ico, suppress=True)\n", " draw_poly(ico, target)\n", " draw_poly(st, target)\n", " for ik in twelve_around_one(ico):\n", " draw_poly(ik, target)\n", " for s in twelve_around_one(st):\n", " draw_poly(s, target, v = False)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{0: {ivm_vector(a=0, b=0, c=0, d=0)},\n", " 1: {ivm_vector(a=0, b=1, c=1, d=2),\n", " ivm_vector(a=0, b=1, c=2, d=1),\n", " ivm_vector(a=0, b=2, c=1, d=1),\n", " ivm_vector(a=1, b=0, c=1, d=2),\n", " ivm_vector(a=1, b=0, c=2, d=1),\n", " ivm_vector(a=1, b=1, c=0, d=2),\n", " ivm_vector(a=1, b=1, c=2, d=0),\n", " ivm_vector(a=1, b=2, c=0, d=1),\n", " ivm_vector(a=1, b=2, c=1, d=0),\n", " ivm_vector(a=2, b=0, c=1, d=1),\n", " ivm_vector(a=2, b=1, c=0, d=1),\n", " ivm_vector(a=2, b=1, c=1, d=0)}}" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "IVM" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "def all_ivm(p):\n", " translations = [ ]\n", " maxlayer = max(IVM.keys())\n", " for layer in range(maxlayer, 0, -1):\n", " for t in IVM[layer]:\n", " translations.append(p + t)\n", " return translations" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "def flextegrity6():\n", " global IVM\n", " IVM = {}\n", " IVM[0] = {Qvector((0,0,0,0))}\n", "\n", " add_layer()\n", " add_layer()\n", "\n", " flextegrity.IVM = IVM\n", "\n", " with open(\"flextegrity6.pov\", \"w\") as target:\n", " target.write(pov_header) \n", " c = Cube()\n", " ico = Icosahedron() * (1/PHI * math.sqrt(2)/2) * 0.7\n", " st = Struts(c, ico, suppress=True)\n", " draw_poly(ico, target)\n", " draw_poly(st, target)\n", " for ik in all_ivm(ico):\n", " draw_poly(ik, target)\n", " for s in all_ivm(st):\n", " draw_poly(s, target, v = False)" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": [ "flextegrity6()" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "def outer_ivm(p):\n", " translations = [ ]\n", " maxlayer = max(IVM.keys())\n", " for t in IVM[maxlayer]:\n", " translations.append(p + t)\n", " return translations\n", "\n", "def flextegrity7():\n", " global IVM\n", " IVM = {}\n", " IVM[0] = {Qvector((0,0,0,0))}\n", "\n", " add_layer()\n", " add_layer()\n", " add_layer()\n", " \n", " del IVM[2]\n", " del IVM[1]\n", " del IVM[0]\n", " \n", " flextegrity.IVM = IVM\n", "\n", " with open(\"flextegrity7.pov\", \"w\") as target:\n", " target.write(pov_header) \n", " c = Cube()\n", " cubo = Cuboctahedron() * 3\n", " ico = Icosahedron() * (1/PHI * math.sqrt(2)/2)\n", " st = Struts(c, ico, suppress=True)\n", " draw_poly(cubo, target)\n", " #draw_poly(st, target)\n", " for ik in outer_ivm(ico):\n", " draw_poly(ik, target)\n", " for s in outer_ivm(st):\n", " draw_poly(s, target, v = False)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "flextegrity7()" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "// Persistence of Vision Ray Tracer Scene Description File\n", "// File: xyz.pov\n", "// Vers: 3.6\n", "// Desc: test file\n", "// Date: Sat Sep 7 09:49:33 2019\n", "// Auth: me\n", "// ==== Standard POV-Ray Includes ====\n", "#include \"colors.inc\" // Standard Color definitions\n", "// include \"textures.inc\" // Standard Texture definitions\n", "// include \"functions.inc\" // internal functions usable in user defined functions\n", "\n", "// ==== Additional Includes ====\n", "// Don't have all of the following included at once, it'll cost memory and time\n", "// to parse!\n", "// --- general include files ---\n", "// include \"chars.inc\" // A complete library of character objects, by Ken Maeno\n", "// include \"skies.inc\" // Ready defined sky spheres\n", "// include \"stars.inc\" // Some star fields\n", "// include \"strings.inc\" // macros for generating and manipulating text strings\n", "\n", "// --- textures ---\n", "// include \"finish.inc\" // Some basic finishes\n", "// include \"glass.inc\" // Glass textures/interiors\n", "// include \"golds.inc\" // Gold textures\n", "// include \"metals.inc\" // Metallic pigments, finishes, and textures\n", "// include \"stones.inc\" // Binding include-file for STONES1 and STONES2\n", "// include \"stones1.inc\" // Great stone-textures created by Mike Miller\n", "// include \"stones2.inc\" // More, done by Dan Farmer and Paul Novak\n", "// include \"woodmaps.inc\" // Basic wooden colormaps\n", "// include \"woods.inc\" // Great wooden textures created by Dan Farmer and Paul Novak\n", "\n", "global_settings {assumed_gamma 1.0}\n", "global_settings {ambient_light rgb<1, 1, 1> }\n", "\n", "// perspective (default) camera\n", "camera {\n", " location <6, 0.1, 0.2>\n", " rotate <45, 45, 10.0>\n", " look_at <0.0, 0.0, 0.0>\n", " right x*image_width/image_height\n", "}\n", "\n", "// create a regular point light source\n", "light_source {\n", " 0*x // light's position (translated below)\n", " color rgb <1,1,1> // light's color\n", " translate <-20, 15, 10>\n", "}\n", "\n", "// create a regular point light source\n", "light_source {\n", " 0*x // light's position (translated below)\n", " color rgb <1,1,1> // light's color\n", " translate <20, -15, -10>\n", "}\n", "\n", "background { color rgb <1.0, 1.0, 1.0> }\n", "\n" ] } ], "source": [ "print(pov_header)" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": [ "with open(\"pov_header_snapshot_rotation.pov\", \"w\") as f:\n", " f.write(pov_header)" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "# pov_header = pov_header.replace(\"look_at <0.0, 0.0, 0.0>\", \"look_at <0.0, -1.0, 0.0>\")\n", "pov_header = pov_header.replace(\"rotate <45, 45, 10.0>\", \"// rotate <0, -2, 10.0>\")\n", "# pov_header = pov_header.replace(\"rotate <45, 45, 10.0>\", \"rotate <0, -2, 10.0>\")\n", "# pov_header = pov_header.replace(\"location <8, 0.1, 0.2>\", \"location <10, 0.1, 0.2>\")" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [], "source": [ "def flextegrity_film(r, frame):\n", "\n", " with open(frame, \"w\") as target:\n", " \n", " target.write(pov_header) \n", " c = Cube()\n", " ico = Icosahedron() * (1/PHI * math.sqrt(2)/2) * r\n", " st = Struts(c, ico, suppress=True)\n", " draw_poly(ico, target)\n", " draw_poly(st, target)\n", " for ik in all_ivm(ico):\n", " draw_poly(ik, target)\n", " for s in all_ivm(st):\n", " draw_poly(s, target, v = False)" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "\n", "global IVM\n", "IVM = {}\n", "IVM[0] = {Qvector((0,0,0,0))}\n", "\n", "add_layer()\n", "add_layer()\n", "\n", "flextegrity.IVM = IVM\n", "\n", "def animation6(targdir=\"anim6\"):\n", " \n", " targdir = os.path.join(\".\",targdir)\n", " if not os.path.isdir(targdir):\n", " os.mkdir(targdir)\n", " \n", " radii = np.linspace(0.6, 1.3, 8).tolist()\n", " radii += reversed(radii[1:-1])\n", " for frame_id, radius in enumerate(radii, start=1):\n", " filename = os.path.join(targdir,f\"balls{frame_id:03}.pov\")\n", " flextegrity_film(radius, filename)" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "animation6()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![cubocta](https://upload.wikimedia.org/wikipedia/commons/d/dc/Povlabels.gif)" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "from flextegrity import U,X,V\n", "\n", "def add_tet_layer():\n", " global IVM\n", " directions = [U,X,V]\n", " maxlayer = max(IVM.keys())\n", " nextlayer = maxlayer + 1\n", " the_set = set()\n", " for idx, center in enumerate(IVM[maxlayer]):\n", " # print(idx)\n", " for v in directions:\n", " candidate = center + v\n", " # print(\"Checking\", candidate)\n", " if (candidate in IVM[maxlayer]):\n", " # print(candidate, \"no good\")\n", " continue\n", " if (maxlayer-1 in IVM) and (candidate in IVM[maxlayer-1]):\n", " # print(candidate, \"no good\")\n", " continue\n", " # print(candidate, \"OK!\")\n", " the_set.add(candidate)\n", " \n", " IVM[nextlayer] = the_set " ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Not found!\n" ] } ], "source": [ "import numpy as np\n", "\n", "edges = set()\n", "\n", "global IVM\n", "IVM = {}\n", "IVM[0] = {Qvector((0,0,0,0))}\n", "\n", "add_tet_layer()\n", "add_tet_layer()\n", "add_tet_layer()\n", "add_tet_layer()\n", "\n", "flextegrity.IVM = IVM\n", "\n", "cubocta = Cuboctahedron()\n", "cubocta.vert_radius = 0.03\n", "cubocta.vert_color = \"rgb <1,0,0>\"\n", "\n", "targdir=\"anim8\"\n", "targdir = os.path.join(\".\",targdir)\n", "if not os.path.isdir(targdir):\n", " os.mkdir(targdir)\n", " \n", "for frame_id, angle in enumerate(range(0,360,2), start=1):\n", " filename = os.path.join(targdir,f\"balls{frame_id:03}.pov\")\n", " if not f\"rotate <0, {angle-2}, 10.0>\" in pov_header:\n", " print(\"Not found!\")\n", " break\n", " else:\n", " pov_header = pov_header.replace(f\"rotate <0, {angle-2}, 10.0>\", f\"rotate <0, {angle}, 10.0>\")\n", " assert f\"rotate <0, {angle}, 10.0>\" in pov_header\n", " \n", " with open(filename, \"w\") as target:\n", " target.write(pov_header) \n", " for ball in all_ivm( Qvector((0,0,0,0)) ):\n", " draw_vert(ball, c=cubocta.vert_color, \n", " r=cubocta.vert_radius, t=target)\n", "\n", " get_edges()\n", " for e in make_edge_list():\n", " draw_edge(e, c=cubocta.vert_color, \n", " r=cubocta.vert_radius, t=target)" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [], "source": [ "with open(\"pov_header_snapshot_rotation.pov\", \"r\") as f:\n", " pov_header = f.read()" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Not found!\n" ] } ], "source": [ "edges = set()\n", "\n", "global IVM\n", "IVM = {}\n", "IVM[0] = {Qvector((0,0,0,0))}\n", "\n", "add_tet_layer()\n", "add_tet_layer()\n", "add_tet_layer()\n", "add_tet_layer()\n", "\n", "flextegrity.IVM = IVM\n", "\n", "cubocta = Cuboctahedron()\n", "cubocta.vert_radius = 0.03\n", "cubocta.vert_color = \"rgb <1,0,0>\"\n", "\n", "targdir=\"anim9\"\n", "targdir = os.path.join(\".\",targdir)\n", "if not os.path.isdir(targdir):\n", " os.mkdir(targdir)\n", " \n", "for frame_id, angle in enumerate(range(0,360,2), start=1):\n", " filename = os.path.join(targdir,f\"balls{frame_id:03}.pov\")\n", " if not f\"rotate <0, {angle-2}, 10.0>\" in pov_header:\n", " print(\"Not found!\")\n", " break\n", " else:\n", " pov_header = pov_header.replace(f\"rotate <0, {angle-2}, 10.0>\", f\"rotate <0, {angle}, 10.0>\")\n", " assert f\"rotate <0, {angle}, 10.0>\" in pov_header\n", " \n", " with open(filename, \"w\") as target:\n", " target.write(pov_header)\n", " \n", " if 1 <= frame_id <= 90:\n", " draw_vert(Qvector((0,0,0,0)), c=cubocta.vert_color, \n", " r=0.5*frame_id/90, t=target)\n", " for ball in all_ivm( Qvector((0,0,0,0)) ):\n", " draw_vert(ball, c=cubocta.vert_color, \n", " r=0.5*frame_id/135, t=target)\n", " \n", " if 90 < frame_id <= 180:\n", " draw_vert(Qvector((0,0,0,0)), c=cubocta.vert_color, \n", " r=0.5*(180-frame_id)/90, t=target)\n", " for ball in all_ivm( Qvector((0,0,0,0)) ):\n", " draw_vert(ball, c=cubocta.vert_color, \n", " r=0.5*(180-frame_id)/90, t=target)\n", " \n", " if (0 <= frame_id < 65) or (125 <= frame_id <= 180):\n", " get_edges()\n", " for e in make_edge_list():\n", " draw_edge(e, c=cubocta.vert_color, \n", " r=cubocta.vert_radius, t=target)\n", " \n", " rd = RD()\n", " draw_poly(rd, target)\n", " for p in all_ivm(rd):\n", " draw_poly(p, target)" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "2 <= 3" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [], "source": [ "import flex_scripts" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [], "source": [ "flex_scripts.animation5()" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Processing... /usr/local/bin/povray +A +H768 +W1024 ./balls000.pov\n", "Processing... /usr/local/bin/povray +A +H768 +W1024 ./balls001.pov\n", "Processing... /usr/local/bin/povray +A +H768 +W1024 ./balls002.pov\n", "Processing... /usr/local/bin/povray +A +H768 +W1024 ./balls003.pov\n", "Processing... /usr/local/bin/povray +A +H768 +W1024 ./balls004.pov\n", "Processing... /usr/local/bin/povray +A +H768 +W1024 ./balls005.pov\n", "Processing... /usr/local/bin/povray +A +H768 +W1024 ./balls006.pov\n", "Processing... /usr/local/bin/povray +A +H768 +W1024 ./balls007.pov\n", "Processing... /usr/local/bin/povray +A +H768 +W1024 ./balls008.pov\n", "Processing... /usr/local/bin/povray +A +H768 +W1024 ./balls009.pov\n", "Processing... /usr/local/bin/povray +A +H768 +W1024 ./balls010.pov\n", "Processing... /usr/local/bin/povray +A +H768 +W1024 ./balls011.pov\n", "Processing... /usr/local/bin/povray +A +H768 +W1024 ./balls012.pov\n" ] } ], "source": [ "import os\n", "os.chdir('/Users/mac/Documents/School_of_Tomorrow/anim11')\n", "files = sorted([fname for fname in os.listdir(\".\") if \".pov\" in fname])\n", "for f in files:\n", " cmd = \"/usr/local/bin/povray +A +H768 +W1024 ./{}\".format(f)\n", " print(\"Processing...\", cmd)\n", " output = os.system(cmd) " ] } ], "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.7.9" } }, "nbformat": 4, "nbformat_minor": 4 }