diff --git a/Documentation/sphinx-docs/build/doctrees/applications.doctree b/Documentation/sphinx-docs/build/doctrees/applications.doctree new file mode 100644 index 000000000..4ed670691 Binary files /dev/null and b/Documentation/sphinx-docs/build/doctrees/applications.doctree differ diff --git a/Documentation/sphinx-docs/build/doctrees/dfnflow.doctree b/Documentation/sphinx-docs/build/doctrees/dfnflow.doctree new file mode 100644 index 000000000..3fff45585 Binary files /dev/null and b/Documentation/sphinx-docs/build/doctrees/dfnflow.doctree differ diff --git a/Documentation/sphinx-docs/build/doctrees/dfngen.doctree b/Documentation/sphinx-docs/build/doctrees/dfngen.doctree new file mode 100644 index 000000000..876dae493 Binary files /dev/null and b/Documentation/sphinx-docs/build/doctrees/dfngen.doctree differ diff --git a/Documentation/sphinx-docs/build/doctrees/dfntrans.doctree b/Documentation/sphinx-docs/build/doctrees/dfntrans.doctree new file mode 100644 index 000000000..04b10a036 Binary files /dev/null and b/Documentation/sphinx-docs/build/doctrees/dfntrans.doctree differ diff --git a/Documentation/sphinx-docs/build/doctrees/environment.pickle b/Documentation/sphinx-docs/build/doctrees/environment.pickle new file mode 100644 index 000000000..ead435c80 Binary files /dev/null and b/Documentation/sphinx-docs/build/doctrees/environment.pickle differ diff --git a/Documentation/sphinx-docs/build/doctrees/examples.doctree b/Documentation/sphinx-docs/build/doctrees/examples.doctree new file mode 100644 index 000000000..062223dd4 Binary files /dev/null and b/Documentation/sphinx-docs/build/doctrees/examples.doctree differ diff --git a/Documentation/sphinx-docs/build/doctrees/gallery.doctree b/Documentation/sphinx-docs/build/doctrees/gallery.doctree new file mode 100644 index 000000000..341513bdc Binary files /dev/null and b/Documentation/sphinx-docs/build/doctrees/gallery.doctree differ diff --git a/Documentation/sphinx-docs/build/doctrees/index_docs.doctree b/Documentation/sphinx-docs/build/doctrees/index_docs.doctree new file mode 100644 index 000000000..903b36ae6 Binary files /dev/null and b/Documentation/sphinx-docs/build/doctrees/index_docs.doctree differ diff --git a/Documentation/sphinx-docs/build/doctrees/intro.doctree b/Documentation/sphinx-docs/build/doctrees/intro.doctree new file mode 100644 index 000000000..9288fe95d Binary files /dev/null and b/Documentation/sphinx-docs/build/doctrees/intro.doctree differ diff --git a/Documentation/sphinx-docs/build/doctrees/output.doctree b/Documentation/sphinx-docs/build/doctrees/output.doctree new file mode 100644 index 000000000..9ceca5c3b Binary files /dev/null and b/Documentation/sphinx-docs/build/doctrees/output.doctree differ diff --git a/Documentation/sphinx-docs/build/doctrees/publications.doctree b/Documentation/sphinx-docs/build/doctrees/publications.doctree new file mode 100644 index 000000000..6934bcf99 Binary files /dev/null and b/Documentation/sphinx-docs/build/doctrees/publications.doctree differ diff --git a/Documentation/sphinx-docs/build/doctrees/pydfnFlow.doctree b/Documentation/sphinx-docs/build/doctrees/pydfnFlow.doctree new file mode 100644 index 000000000..e33b0aa2f Binary files /dev/null and b/Documentation/sphinx-docs/build/doctrees/pydfnFlow.doctree differ diff --git a/Documentation/sphinx-docs/build/doctrees/pydfnGen.doctree b/Documentation/sphinx-docs/build/doctrees/pydfnGen.doctree new file mode 100644 index 000000000..76e952621 Binary files /dev/null and b/Documentation/sphinx-docs/build/doctrees/pydfnGen.doctree differ diff --git a/Documentation/sphinx-docs/build/doctrees/pydfnGraph.doctree b/Documentation/sphinx-docs/build/doctrees/pydfnGraph.doctree new file mode 100644 index 000000000..720d2e1ce Binary files /dev/null and b/Documentation/sphinx-docs/build/doctrees/pydfnGraph.doctree differ diff --git a/Documentation/sphinx-docs/build/doctrees/pydfnTrans.doctree b/Documentation/sphinx-docs/build/doctrees/pydfnTrans.doctree new file mode 100644 index 000000000..beb3d42b2 Binary files /dev/null and b/Documentation/sphinx-docs/build/doctrees/pydfnTrans.doctree differ diff --git a/Documentation/sphinx-docs/build/doctrees/pydfnWorks-well.doctree b/Documentation/sphinx-docs/build/doctrees/pydfnWorks-well.doctree new file mode 100644 index 000000000..ff1ca33bb Binary files /dev/null and b/Documentation/sphinx-docs/build/doctrees/pydfnWorks-well.doctree differ diff --git a/Documentation/sphinx-docs/build/doctrees/pydfnworks.doctree b/Documentation/sphinx-docs/build/doctrees/pydfnworks.doctree new file mode 100644 index 000000000..32f15df38 Binary files /dev/null and b/Documentation/sphinx-docs/build/doctrees/pydfnworks.doctree differ diff --git a/Documentation/sphinx-docs/build/doctrees/setup.doctree b/Documentation/sphinx-docs/build/doctrees/setup.doctree new file mode 100644 index 000000000..ed5e89e67 Binary files /dev/null and b/Documentation/sphinx-docs/build/doctrees/setup.doctree differ diff --git a/Documentation/sphinx-docs/build/html/.buildinfo b/Documentation/sphinx-docs/build/html/.buildinfo new file mode 100644 index 000000000..9fda04e42 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 4a2b3cee4617f100cc47d64a83133f7d +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/Documentation/sphinx-docs/build/html/_images/4_user_ellipses.png b/Documentation/sphinx-docs/build/html/_images/4_user_ellipses.png new file mode 100644 index 000000000..ff54ce38c Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/4_user_ellipses.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/4_user_rectangles.png b/Documentation/sphinx-docs/build/html/_images/4_user_rectangles.png new file mode 100644 index 000000000..9d3d72832 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/4_user_rectangles.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/TPL_pathlines.png b/Documentation/sphinx-docs/build/html/_images/TPL_pathlines.png new file mode 100644 index 000000000..ca89520ae Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/TPL_pathlines.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/dead-end_velocity_field.png b/Documentation/sphinx-docs/build/html/_images/dead-end_velocity_field.png new file mode 100644 index 000000000..7e19a5701 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/dead-end_velocity_field.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/dfn_2_core.png b/Documentation/sphinx-docs/build/html/_images/dfn_2_core.png new file mode 100644 index 000000000..40c793d78 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/dfn_2_core.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/dfn_graph.png b/Documentation/sphinx-docs/build/html/_images/dfn_graph.png new file mode 100644 index 000000000..0ee60196a Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/dfn_graph.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/exp_pressure.png b/Documentation/sphinx-docs/build/html/_images/exp_pressure.png new file mode 100644 index 000000000..00426abee Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/exp_pressure.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/forsmark_trajectories.png b/Documentation/sphinx-docs/build/html/_images/forsmark_trajectories.png new file mode 100644 index 000000000..24bf850d7 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/forsmark_trajectories.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/in-fracture-variability_pathlines.png b/Documentation/sphinx-docs/build/html/_images/in-fracture-variability_pathlines.png new file mode 100644 index 000000000..68c854dd1 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/in-fracture-variability_pathlines.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/02c849aad7960bc828467cc5933f8fe020201c4b.png b/Documentation/sphinx-docs/build/html/_images/math/02c849aad7960bc828467cc5933f8fe020201c4b.png new file mode 100644 index 000000000..2081048ca Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/02c849aad7960bc828467cc5933f8fe020201c4b.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/261e3eb56c1757dd003745ee4cc53aa595565af1.png b/Documentation/sphinx-docs/build/html/_images/math/261e3eb56c1757dd003745ee4cc53aa595565af1.png new file mode 100644 index 000000000..1cf9581f4 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/261e3eb56c1757dd003745ee4cc53aa595565af1.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/279e5f07d040abb28b85734dce062ae251eb1c7b.png b/Documentation/sphinx-docs/build/html/_images/math/279e5f07d040abb28b85734dce062ae251eb1c7b.png new file mode 100644 index 000000000..a77972078 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/279e5f07d040abb28b85734dce062ae251eb1c7b.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/2e0bcb32a282b693f93afdd203ce17b9b558ff79.png b/Documentation/sphinx-docs/build/html/_images/math/2e0bcb32a282b693f93afdd203ce17b9b558ff79.png new file mode 100644 index 000000000..74be8eccc Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/2e0bcb32a282b693f93afdd203ce17b9b558ff79.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/2f5aa019312e1bbc969deab8dca8b00f76025404.png b/Documentation/sphinx-docs/build/html/_images/math/2f5aa019312e1bbc969deab8dca8b00f76025404.png new file mode 100644 index 000000000..b2f688172 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/2f5aa019312e1bbc969deab8dca8b00f76025404.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/345f606ec4423cb6fa147f63a5da5a98ee48c1bb.png b/Documentation/sphinx-docs/build/html/_images/math/345f606ec4423cb6fa147f63a5da5a98ee48c1bb.png new file mode 100644 index 000000000..9f0482013 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/345f606ec4423cb6fa147f63a5da5a98ee48c1bb.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/36bc2e342149719661caf719641e17da4ee2dfe6.png b/Documentation/sphinx-docs/build/html/_images/math/36bc2e342149719661caf719641e17da4ee2dfe6.png new file mode 100644 index 000000000..576a09086 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/36bc2e342149719661caf719641e17da4ee2dfe6.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/416cf0520ab360f9e5d8f8e778bb5657fe846cbb.png b/Documentation/sphinx-docs/build/html/_images/math/416cf0520ab360f9e5d8f8e778bb5657fe846cbb.png new file mode 100644 index 000000000..a910a8731 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/416cf0520ab360f9e5d8f8e778bb5657fe846cbb.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/49c53391daff97aa7d155674c12e14f9e6ba1c93.png b/Documentation/sphinx-docs/build/html/_images/math/49c53391daff97aa7d155674c12e14f9e6ba1c93.png new file mode 100644 index 000000000..bd22318d0 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/49c53391daff97aa7d155674c12e14f9e6ba1c93.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/4a3598141469c2555591e66606a1b86d4ec6dca9.png b/Documentation/sphinx-docs/build/html/_images/math/4a3598141469c2555591e66606a1b86d4ec6dca9.png new file mode 100644 index 000000000..cec2dcc89 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/4a3598141469c2555591e66606a1b86d4ec6dca9.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/4ed396e004eb768a13e92e60d6ec6ca2d8406bc3.png b/Documentation/sphinx-docs/build/html/_images/math/4ed396e004eb768a13e92e60d6ec6ca2d8406bc3.png new file mode 100644 index 000000000..25fe95682 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/4ed396e004eb768a13e92e60d6ec6ca2d8406bc3.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/5406eadc281dbd20de843b0034c8497320dae5cb.png b/Documentation/sphinx-docs/build/html/_images/math/5406eadc281dbd20de843b0034c8497320dae5cb.png new file mode 100644 index 000000000..76f5792c4 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/5406eadc281dbd20de843b0034c8497320dae5cb.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/5b514159f8b6bf75e6317d628c7caf2df737075c.png b/Documentation/sphinx-docs/build/html/_images/math/5b514159f8b6bf75e6317d628c7caf2df737075c.png new file mode 100644 index 000000000..a3542dea8 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/5b514159f8b6bf75e6317d628c7caf2df737075c.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/5f01a802667a3ba5b8994a25f3fdf78bf8593563.png b/Documentation/sphinx-docs/build/html/_images/math/5f01a802667a3ba5b8994a25f3fdf78bf8593563.png new file mode 100644 index 000000000..80bceaaea Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/5f01a802667a3ba5b8994a25f3fdf78bf8593563.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/5fd160b4cce0043bb255b69534567d66c7701e55.png b/Documentation/sphinx-docs/build/html/_images/math/5fd160b4cce0043bb255b69534567d66c7701e55.png new file mode 100644 index 000000000..d5e9f2ab4 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/5fd160b4cce0043bb255b69534567d66c7701e55.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/64cfd851ec561560ab02a61550edfe6939966211.png b/Documentation/sphinx-docs/build/html/_images/math/64cfd851ec561560ab02a61550edfe6939966211.png new file mode 100644 index 000000000..ef1c1d0a2 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/64cfd851ec561560ab02a61550edfe6939966211.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/68c7c8c65602677ab56cf7fd88002023f0edc575.png b/Documentation/sphinx-docs/build/html/_images/math/68c7c8c65602677ab56cf7fd88002023f0edc575.png new file mode 100644 index 000000000..30e812bc0 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/68c7c8c65602677ab56cf7fd88002023f0edc575.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/6cf2be4eba28e4c7a7daec65d0075aae07bb173e.png b/Documentation/sphinx-docs/build/html/_images/math/6cf2be4eba28e4c7a7daec65d0075aae07bb173e.png new file mode 100644 index 000000000..fbb617397 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/6cf2be4eba28e4c7a7daec65d0075aae07bb173e.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/73f4958e89c005c29b46fe025be4584c439caa4b.png b/Documentation/sphinx-docs/build/html/_images/math/73f4958e89c005c29b46fe025be4584c439caa4b.png new file mode 100644 index 000000000..e769e1441 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/73f4958e89c005c29b46fe025be4584c439caa4b.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/761a700ecec9ede79c472b840375d1398c81a1aa.png b/Documentation/sphinx-docs/build/html/_images/math/761a700ecec9ede79c472b840375d1398c81a1aa.png new file mode 100644 index 000000000..eaf672c8c Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/761a700ecec9ede79c472b840375d1398c81a1aa.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/7dfd566f04990e72a20ff38301773d0a0cf37845.png b/Documentation/sphinx-docs/build/html/_images/math/7dfd566f04990e72a20ff38301773d0a0cf37845.png new file mode 100644 index 000000000..9e3b9646c Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/7dfd566f04990e72a20ff38301773d0a0cf37845.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/8a87f04e7d7cca18343c084cceca5237fae62491.png b/Documentation/sphinx-docs/build/html/_images/math/8a87f04e7d7cca18343c084cceca5237fae62491.png new file mode 100644 index 000000000..4a9f9be48 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/8a87f04e7d7cca18343c084cceca5237fae62491.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/8cf77d2801619424ae7a84211bb1a8cca8795192.png b/Documentation/sphinx-docs/build/html/_images/math/8cf77d2801619424ae7a84211bb1a8cca8795192.png new file mode 100644 index 000000000..578948f48 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/8cf77d2801619424ae7a84211bb1a8cca8795192.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/9630132210b904754c9ab272b61cb527d12263ca.png b/Documentation/sphinx-docs/build/html/_images/math/9630132210b904754c9ab272b61cb527d12263ca.png new file mode 100644 index 000000000..fe54e2443 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/9630132210b904754c9ab272b61cb527d12263ca.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/a093d21e837b340ae5112488ff176fc6c8492c87.png b/Documentation/sphinx-docs/build/html/_images/math/a093d21e837b340ae5112488ff176fc6c8492c87.png new file mode 100644 index 000000000..4ea4381bb Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/a093d21e837b340ae5112488ff176fc6c8492c87.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/a20864ec4268c5cf0fdd0c4e76a69bbb74733b54.png b/Documentation/sphinx-docs/build/html/_images/math/a20864ec4268c5cf0fdd0c4e76a69bbb74733b54.png new file mode 100644 index 000000000..4817d4773 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/a20864ec4268c5cf0fdd0c4e76a69bbb74733b54.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/a963655a01fb22852c131f0d8e66066026c39fb8.png b/Documentation/sphinx-docs/build/html/_images/math/a963655a01fb22852c131f0d8e66066026c39fb8.png new file mode 100644 index 000000000..a3ab94e9a Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/a963655a01fb22852c131f0d8e66066026c39fb8.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/a9a7d5b5b78fb63c537c462714d97ffd7c091829.png b/Documentation/sphinx-docs/build/html/_images/math/a9a7d5b5b78fb63c537c462714d97ffd7c091829.png new file mode 100644 index 000000000..fca7fb293 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/a9a7d5b5b78fb63c537c462714d97ffd7c091829.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/af5573a7b3374f4e3287488adf152892c0f16488.png b/Documentation/sphinx-docs/build/html/_images/math/af5573a7b3374f4e3287488adf152892c0f16488.png new file mode 100644 index 000000000..0f1152a01 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/af5573a7b3374f4e3287488adf152892c0f16488.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/b4ecdaef430093e2c63ec36545fdc953d7b1449c.png b/Documentation/sphinx-docs/build/html/_images/math/b4ecdaef430093e2c63ec36545fdc953d7b1449c.png new file mode 100644 index 000000000..d65283fad Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/b4ecdaef430093e2c63ec36545fdc953d7b1449c.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/b52df27bfb0b1e3af0c2c68a7b9da459178c2a7d.png b/Documentation/sphinx-docs/build/html/_images/math/b52df27bfb0b1e3af0c2c68a7b9da459178c2a7d.png new file mode 100644 index 000000000..7a4ae42dc Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/b52df27bfb0b1e3af0c2c68a7b9da459178c2a7d.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/bf4d6dded1f2769dd9942a7e0071045945dbeb9a.png b/Documentation/sphinx-docs/build/html/_images/math/bf4d6dded1f2769dd9942a7e0071045945dbeb9a.png new file mode 100644 index 000000000..e26a15b52 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/bf4d6dded1f2769dd9942a7e0071045945dbeb9a.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/cefc603e5658facb747581f9567192993f21c7ab.png b/Documentation/sphinx-docs/build/html/_images/math/cefc603e5658facb747581f9567192993f21c7ab.png new file mode 100644 index 000000000..749d58820 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/cefc603e5658facb747581f9567192993f21c7ab.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/d549c46bd87138576a59f5cb8578b1e7c7ba4344.png b/Documentation/sphinx-docs/build/html/_images/math/d549c46bd87138576a59f5cb8578b1e7c7ba4344.png new file mode 100644 index 000000000..7a48fbceb Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/d549c46bd87138576a59f5cb8578b1e7c7ba4344.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/e24906bf3a64d622f266503cd7146a8de74a258d.png b/Documentation/sphinx-docs/build/html/_images/math/e24906bf3a64d622f266503cd7146a8de74a258d.png new file mode 100644 index 000000000..2c550f197 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/e24906bf3a64d622f266503cd7146a8de74a258d.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/e8dea8254118f111b5fb20895b03528c17566f06.png b/Documentation/sphinx-docs/build/html/_images/math/e8dea8254118f111b5fb20895b03528c17566f06.png new file mode 100644 index 000000000..f3b3569b3 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/e8dea8254118f111b5fb20895b03528c17566f06.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/ef0f29bda011efb4abda29f5620732e335ad5e42.png b/Documentation/sphinx-docs/build/html/_images/math/ef0f29bda011efb4abda29f5620732e335ad5e42.png new file mode 100644 index 000000000..05ac3b5dd Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/ef0f29bda011efb4abda29f5620732e335ad5e42.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/f709b2722911463d06271f2320d386c4f3ab88fe.png b/Documentation/sphinx-docs/build/html/_images/math/f709b2722911463d06271f2320d386c4f3ab88fe.png new file mode 100644 index 000000000..4da1399dc Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/f709b2722911463d06271f2320d386c4f3ab88fe.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/ff4552ec4e1115499121b2cc24265a14c7aa7b1c.png b/Documentation/sphinx-docs/build/html/_images/math/ff4552ec4e1115499121b2cc24265a14c7aa7b1c.png new file mode 100644 index 000000000..42ec8a8a9 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/ff4552ec4e1115499121b2cc24265a14c7aa7b1c.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/math/fffd2357ee88a9c50ba9e831ed64c39c73d54a07.png b/Documentation/sphinx-docs/build/html/_images/math/fffd2357ee88a9c50ba9e831ed64c39c73d54a07.png new file mode 100644 index 000000000..ba6e83da0 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/math/fffd2357ee88a9c50ba9e831ed64c39c73d54a07.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/power_mesh.png b/Documentation/sphinx-docs/build/html/_images/power_mesh.png new file mode 100644 index 000000000..6ee3f416e Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/power_mesh.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/pruned_network.png b/Documentation/sphinx-docs/build/html/_images/pruned_network.png new file mode 100644 index 000000000..77a9f4001 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/pruned_network.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/time_co2.png b/Documentation/sphinx-docs/build/html/_images/time_co2.png new file mode 100644 index 000000000..1711076f1 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/time_co2.png differ diff --git a/Documentation/sphinx-docs/build/html/_images/well-pressure.png b/Documentation/sphinx-docs/build/html/_images/well-pressure.png new file mode 100644 index 000000000..f0f528b47 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_images/well-pressure.png differ diff --git a/Documentation/sphinx-docs/build/html/_modules/index.html b/Documentation/sphinx-docs/build/html/_modules/index.html new file mode 100644 index 000000000..b51063b9a --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/index.html @@ -0,0 +1,144 @@ + + + + + + Overview: module code — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnFlow/fehm.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnFlow/fehm.html new file mode 100644 index 000000000..9f993d749 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnFlow/fehm.html @@ -0,0 +1,261 @@ + + + + + + pydfnworks.dfnFlow.fehm — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for pydfnworks.dfnFlow.fehm

+import os
+import subprocess
+import sys
+import glob
+import shutil
+from time import time
+import numpy as np
+"""
+Functions for using FEHM in dfnWorks
+"""
+
+
+
+[docs] +def correct_stor_file(self): + """Corrects volumes in stor file to account for apertures + + Parameters + ---------- + self : object + DFN Class + + Returns + -------- + None + + Notes + -------- + Currently does not work with cell based aperture + """ + # Make input file for C Stor converter + if self.flow_solver != "FEHM": + error = "Error. Incorrect flow solver requested\n" + sys.stderr.write(error) + sys.exit(1) + + self.dump_hydraulic_values(format = "FEHM") + + self.stor_file = self.inp_file[:-4] + '.stor' + self.mat_file = self.inp_file[:-4] + '_material.zone' + with open("convert_stor_params.txt", "w") as f: + f.write("%s\n" % self.mat_file) + f.write("%s\n" % self.stor_file) + f.write("%s" % (self.stor_file[:-5] + '_vol_area.stor\n')) + f.write("%s\n" % self.aper_file) + + t = time() + cmd = os.environ['CORRECT_STOR_EXE'] + ' convert_stor_params.txt' + failure = subprocess.call(cmd, shell=True) + if failure > 0: + error = 'ERROR: stor conversion failed\nExiting Program\n' + sys.stderr.write(error) + sys.exit(1) + elapsed = time() - t + print('--> Time elapsed for STOR file conversion: %0.3f seconds\n' % + elapsed)
+ + + +def correct_perm_for_fehm(): + """ FEHM wants an empty line at the end of the perm file + This functions adds that line return + + Parameters + ---------- + None + + Returns + --------- + None + + Notes + ------------ + Only adds a new line if the last line is not empty + """ + fp = open("perm.dat") + lines = fp.readlines() + fp.close() + # Check if the last line of file is just a new line + # If it is not, then add a new line at the end of the file + if len(lines[-1].split()) != 0: + print("--> Adding line to perm.dat") + fp = open("perm.dat", "a") + fp.write("\n") + fp.close() + + +
+[docs] +def fehm(self): + """Run FEHM + + Parameters + ---------- + self : object + DFN Class + + Returns + ------- + None + + Notes + ----- + See https://fehm.lanl.gov/ for details about FEHM + + """ + print("--> Running FEHM") + if self.flow_solver != "FEHM": + error = "Error. Incorrect flow solver requested\n" + sys.stderr.write(error) + sys.exit(1) + + try: + shutil.copy(self.dfnFlow_file, self.jobname) + except: + error = f"--> Error copying FEHM run file: {self.dfnFlow_file}" + sys.stderr.write(error) + sys.exit(1) + + path = self.dfnFlow_file.strip(self.local_dfnFlow_file) + fp = open(self.local_dfnFlow_file) + line = fp.readline() + fehm_input = line.split()[-1] + fp.close() + try: + shutil.copy(path + fehm_input, os.getcwd()) + except: + error = "-->ERROR copying FEHM input file:\n" % fehm_input + sys.stderr.write(error) + sys.exit(1) + + correct_perm_for_fehm() + tic = time() + subprocess.call(os.environ["FEHM_EXE"] + " " + self.local_dfnFlow_file, + shell=True) + print('=' * 80) + print("FEHM Complete") + print("Time Required %0.2f Seconds" % (time() - tic)) + print('=' * 80)
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnFlow/flow.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnFlow/flow.html new file mode 100644 index 000000000..c5688d2ec --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnFlow/flow.html @@ -0,0 +1,262 @@ + + + + + + pydfnworks.dfnFlow.flow — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for pydfnworks.dfnFlow.flow

+import os
+import subprocess
+import sys
+import glob
+import shutil
+from time import time
+import numpy as np
+
+
+
+[docs] +def set_flow_solver(self, flow_solver): + """Sets flow solver to be used + + Parameters + ---------- + self : object + DFN Class + flow_solver: string + Name of flow solver. Currently supported flow sovlers are FEHM and PFLOTRAN + + Returns + --------- + + Notes + -------- + Default is PFLOTRAN + +""" + if flow_solver == "FEHM" or flow_solver == "PFLOTRAN": + print("Using flow solver %s" % flow_solver) + self.flow_solver = flow_solver + else: + error = "ERROR: Unknown flow solver requested %s\nCurrently supported flow solvers are FEHM and PFLOTRAN\nExiting dfnWorks\n" % flow_solver + sys.stderr.write(error) + sys.exit(1)
+ + + +
+[docs] +def dfn_flow(self, dump_vtk=True): + """ Run the dfnFlow portion of the workflow + + Parameters + ---------- + self : object + DFN Class + dump_vtk : bool + True - Write out vtk files for flow solutions + False - Does not write out vtk files for flow solutions + + Returns + --------- + + Notes + -------- + Information on individual functions is found therein + """ + + print('=' * 80) + print("dfnFlow Starting") + print('=' * 80) + + tic_flow = time() + + if self.flow_solver == "PFLOTRAN": + print("Using flow solver: %s" % self.flow_solver) + tic = time() + self.lagrit2pflotran() + self.dump_time('Function: lagrit2pflotran', time() - tic) + + tic = time() + self.pflotran() + self.dump_time('Function: pflotran', time() - tic) + + if dump_vtk: + tic = time() + self.parse_pflotran_vtk_python() + self.dump_time('Function: parse_pflotran_vtk', time() - tic) + tic = time() + self.pflotran_cleanup() + self.dump_time('Function: pflotran_cleanup', time() - tic) + + tic = time() + + elif self.flow_solver == "FEHM": + print("Using flow solver: %s" % self.flow_solver) + tic = time() + self.correct_stor_file() + self.fehm() + self.dump_time('Function: FEHM', time() - tic) + + delta_time = time() - tic_flow + self.dump_time('Process: dfnFlow', delta_time) + + print('=' * 80) + print("dfnFlow Complete") + print("Time Required for dfnFlow %0.2f seconds\n" % delta_time) + print('=' * 80)
+ + + + + +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnFlow/mass_balance.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnFlow/mass_balance.html new file mode 100644 index 000000000..57946503b --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnFlow/mass_balance.html @@ -0,0 +1,382 @@ + + + + + + pydfnworks.dfnFlow.mass_balance — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for pydfnworks.dfnFlow.mass_balance

+#!/usr/bin/env python
+
+# Calculate mass balance across a boundary of a DFN mesh
+# Make sure that you run PFLOTRAN with MASS_FLOWRATE under OUTPUT
+# Satish Karra
+# March 17, 2016
+# Updated Jeffrey Hyman Dec 19 2018
+# Revision Jeffrey Hyman Oct 5 2020
+
+import os
+import numpy as np
+import glob
+
+__author__ = 'Jeffrey Hyman'
+__email__ = 'jhyman@lanl.gov'
+
+def check_inputs(direction, inflow_pressure, outflow_pressure, boundary_file, darcy_vel_file):
+    """
+    Checks that inflow pressure is greater than outflow pressure and that path to file paths are valid. 
+    
+    Parameters
+    ----------------
+        direction : string
+            Primary direction of flow (x, y, or z)
+        inflow_pressure : float 
+            Inflow boundary pressure 
+        outflow_pressure : float 
+            Outflow Boundary pressure
+        boundary_file : string
+            Name of ex file for inflow boundary
+        darcy_vel_file : string
+            name of darcy veloctiy file (pflotran output file)
+
+    Returns 
+    -----------------
+        Boolean 
+            True if all tests pasted, False if not
+
+    """
+
+    if direction not in ['x', 'y', 'z']:
+        print(f"--> Error. Unknown direction provided {direction}. Acceptable values are 'x','y', and 'z'.\nExiting\n"
+        )
+        return False     
+    ## Check Pressure
+    if inflow_pressure < outflow_pressure:
+        print(
+            "--> Error. Inflow pressure is less the outflow pressure. Cannot compute effective permeability.\n"
+        )
+        print(f"--> Inflow Pressure: {inflow_pressure}")
+        print(f"--> Outflow Pressure: {outflow_pressure}")
+        print("Exiting fucntion call.")
+        return False
+
+    if not os.path.exists(boundary_file):
+        print(f"--> Error. Boundary file: {boundary_file} not found. Please check path.\nExiting\n")
+        return False
+    
+
+    if not os.path.exists(darcy_vel_file):
+        print(f"--> Error. Darcy velocity file: {darcy_vel_file} not found. Please check path.\nExiting\n")
+        return False
+    
+    return True
+
+
+def flow_rate(darcy_vel_file, boundary_file):
+    '''Calculates the flow rate across the inflow boundary
+
+    Parameters
+    ----------
+        darcy_vel_file : string
+            Name of concatenated Darcy velocity file
+        boundary_file : string
+             ex file for the inflow boundary
+
+    Returns
+    -------
+        mass_rate : float
+            Mass flow rate across the inflow boundary
+        volume_rate : float
+            Volumetric flow rate across the inflow boundary
+
+    Notes
+    --------
+        None
+'''
+    # Calculate the mass flow rate
+    mass_rate = 0.0  #kg/s
+    volume_rate = 0.0  #m^3/s
+
+    dat_boundary = np.genfromtxt(boundary_file, skip_header=1)
+    dat = np.genfromtxt(darcy_vel_file)
+    for cell in dat_boundary[:, 0]:
+        if (np.any(dat[:, 0] == int(cell))):
+            ids = np.where(dat[:, 0] == int(cell))[0]
+            for idx in ids:
+                cell_up = int(dat[idx, 0])
+                cell_down = int(dat[idx, 1])
+                mass_flux = dat[idx, 2]  # in m/s , darcy flux, right? m3/m2/s
+                density = dat[idx, 3]  # in kg/m3
+                area = dat[idx, 4]  # in m^2
+                if (cell_up == int(cell)):
+                    mass_rate = mass_flux * area * \
+                    density + mass_rate  # in kg/s
+                    volume_rate = mass_flux * area + volume_rate  #in m3/s
+                else:
+                    mass_rate = - mass_flux * area * \
+                    density + mass_rate  # in kg/s
+                    volume_rate = -mass_flux * area + volume_rate  #in m3/s
+                #print cell_up, cell_down, mass_flux, density, area, mass_rate, volume_rate
+        if (np.any(dat[:, 1] == int(cell))):
+            ids = np.where(dat[:, 1] == int(cell))[0]
+            for idx in ids:
+                cell_up = int(dat[idx, 0])
+                cell_down = int(dat[idx, 1])
+                mass_flux = dat[idx, 2]  # in m/s
+                density = dat[idx, 3]  # in kg/m3
+                area = dat[idx, 4]  # in m^2
+                if (cell_up == int(cell)):
+                    mass_rate = mass_flux * area * \
+                    density + mass_rate  # in kg/s
+                    volume_rate = mass_flux * area + volume_rate  #in m3/s
+                else:
+                    mass_rate = - mass_flux * area * \
+                    density + mass_rate  # in kg/s
+                    volume_rate = -mass_flux * area + volume_rate  #in m3/s
+                #print cell_up, cell_down, mass_flux, density, area, mass_rate, volume_rate
+    return mass_rate, volume_rate
+
+
+def dump_effective_perm(local_jobname, mass_rate, volume_rate, domain,
+                        direction, inflow_pressure, outflow_pressure):
+    '''Compute the effective permeability of the DFN and write it to screen and to the file local_jobname_effective_perm.dat
+
+    Parameters
+    ----------
+        local_jobname  : string
+            Jobname
+        mass_rate : float
+            Mass flow rate through inflow boundary
+        volume_rate : float
+            Volumetric flow rate through inflow boundary
+        direction : string
+            Primary direction of flow (x, y, or z)
+        domain : dict
+            Dictionary of domain sizes in x, y, z
+        inflow_pressure : float
+            Inflow boundary pressure
+        outflow_pressure : float
+            Outflow boundary pressure
+
+    Returns
+    -------
+        None
+
+    Notes
+    -----
+        Information is written into <local_jobname>_effective_perm.txt
+'''
+
+    # Lm3 = domain['x'] * domain['y'] * domain['z']  #L/m^3
+    # if flow is in x direction, cross section is domain['y']*domain['z']
+    if direction == 'x':
+        surface = domain['y'] * domain['z']
+        L = domain['x']
+    if direction == 'y':
+        surface = domain['x'] * domain['z']
+        L = domain['y']
+    if direction == 'z':
+        surface = domain['x'] * domain['y']
+        L = domain['z']
+    # Print the calculated mass flow rate in kg/s
+    mu = 8.9e-4  #dynamic viscosity of water at 20 degrees C, Pa*s
+    spery = 3600. * 24. * 365.25  #seconds per year
+    # compute pressure gradient
+    pgrad = (inflow_pressure - outflow_pressure) / L
+    #darcy flux over entire face m3/m2/s
+    q = volume_rate / surface
+
+    output_string = f'''The mass flow rate [kg/s]: {mass_rate:0.5e}
+The volume flow rate [m^3/s]: {volume_rate:0.5e}
+'''
+
+    if direction == 'x':
+        output_string += f'''The Darcy flow rate over {domain['y']} x {domain['z']} m^2 area [m^3/m^2/s]: {q:0.5e}
+The Darcy flow rate over {domain['y']} x {domain['z']} m^2 area [m^3/m^2/y]: {spery*q:0.5e}
+'''
+    elif direction == 'y':
+        output_string += f'''The Darcy flow rate over {domain['x']} x {domain['z']} m^2 area [m^3/m^2/s]: {q:0.5e}
+The Darcy flow rate over {domain['x']} x {domain['z']} m^2 area [m^3/m^2/y]: {spery*q:0.5e}
+'''
+    elif direction == 'y':
+        output_string += f'''The Darcy flow rate over {domain['x']} x {domain['y']} m^2 area [m^3/m^2/s]: {q:0.5e}
+The Darcy flow rate over {domain['x']} x {domain['y']} m^2 area [m^3/m^2/y]: {spery*q:0.5e}
+'''
+    output_string += f'The effective permeability of the domain [m^2]: {q * mu / pgrad:0.5e}'
+    print("\n--> Effective Permeability Properties: ")
+    print(output_string)
+    with open(f'{local_jobname}_effective_perm.txt', "w") as fp:
+        fp.write(output_string)
+    
+    keff = q * mu / pgrad
+    return keff
+
+
+
+[docs] +def effective_perm(self, inflow_pressure, outflow_pressure, boundary_file, + direction, darcy_vel_file = 'darcyvel.dat'): + '''Computes the effective permeability of a DFN in the primary direction of flow using a steady-state PFLOTRAN solution. + + Parameters + ---------- + self : object + DFN Class + inflow_pressure: float + Pressure at the inflow boundary face. Units are Pascal + outflow_pressure: float + Pressure at the outflow boundary face. Units are Pascal + boundary_file: string + Name of inflow boundary file, e.g., pboundary_left.ex + direction: string + Primary direction of flow, x, y, or z + darcy_vel_file : string + Name of concatenated Darcy velocity file + Returns + ------- + None + + Notes + ----- + 1. Information is written to screen and to the file self.local_jobname_effective_perm.txt + 2. Currently, only PFLOTRAN solutions are supported + 3. Assumes density of water at 20c + +''' + + print("--> Computing Effective Permeability of Block\n") + if not self.flow_solver == "PFLOTRAN": + print( + "Incorrect flow solver selected. Cannot compute effective permeability" + ) + return 0 + + print(f"--> Inflow boundary file name:\t\t{boundary_file}") + print(f"--> Darcy Velocity File:\t{darcy_vel_file}") + print(f"--> Inflow Pressure:\t\t{inflow_pressure:0.5e} Pa") + print(f"--> Outflow Pressure:\t\t{outflow_pressure:0.5e} Pa") + print(f"--> Primary Flow Direction:\t{direction}") + + if not check_inputs(direction, inflow_pressure, outflow_pressure, boundary_file, darcy_vel_file): + return 1 + + mass_rate, volume_rate = flow_rate(darcy_vel_file, boundary_file) + keff = dump_effective_perm(self.local_jobname, mass_rate, volume_rate, + self.domain, direction, inflow_pressure, + outflow_pressure) + print("--> Complete\n\n") + self.keff = keff
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnFlow/pflotran.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnFlow/pflotran.html new file mode 100644 index 000000000..de260e825 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnFlow/pflotran.html @@ -0,0 +1,662 @@ + + + + + + pydfnworks.dfnFlow.pflotran — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for pydfnworks.dfnFlow.pflotran

+"""
+functions for using pflotran in dfnworks
+"""
+import os
+import subprocess
+import sys
+import h5py
+import glob
+import shutil
+import ntpath
+from time import time
+import numpy as np
+
+
+
+[docs] +def lagrit2pflotran(self, boundary_cell_area = None): + """ Takes output from LaGriT and processes it for use in PFLOTRAN. + Calls the function write_perms_and_correct_volumes_areas() and zone2ex + + Parameters + -------------- + self : object + DFN Class + + Returns + -------- + None + + Notes + -------- + None + + """ + if self.flow_solver != "PFLOTRAN": + error = "ERROR! Wrong flow solver requested\n" + sys.stderr.write(error) + sys.exit(1) + + print('=' * 80) + print("Starting conversion of files for PFLOTRAN ") + + if self.inp_file == '': + error = 'Error: inp filename not attached to object\n' + sys.stderr.write(error) + sys.exit(1) + + # Check if UGE file was created by LaGriT, if it does not exists, exit + self.uge_file = self.inp_file[:-4] + '.uge' + if not os.path.isfile(self.uge_file): + error = 'Error. Cannot file uge file\nExiting\n' + sys.stderr.write(error) + sys.exit(1) + + self.write_perms_and_correct_volumes_areas() + + if not boundary_cell_area: + boundary_cell_area = 1/self.h + + self.zone2ex(zone_file='all', boundary_cell_area = boundary_cell_area) + self.dump_h5_files() + print("Conversion of files for PFLOTRAN complete") + print('=' * 80) + print("\n\n")
+ + +
+[docs] +def zone2ex(self, zone_file='', face='', boundary_cell_area=1.e-1): + """ + Convert zone files from LaGriT into ex format for LaGriT + + Parameters + ----------- + self : object + DFN Class + zone_file : string + Name of zone file + Face : Face of the plane corresponding to the zone file + zone_file : string + Name of zone file to work on. Can be 'all' processes all directions, top, bottom, left, right, front, back + boundary_cell_area : double + should be a large value relative to the mesh size to force pressure boundary conditions. + + Returns + ---------- + None + + Notes + ---------- + the boundary_cell_area should be a function of h, the mesh resolution + """ + print('*' * 80) + print('--> Converting zone files to ex') + + if self.uge_file == '': + error = 'Error: uge filename not assigned to object yet\n' + sys.stderr.write(error) + sys.exit(1) + + # Opening uge file + print('\n--> Opening uge file') + with open(self.uge_file, 'r') as fuge: + # Reading cell ids, cells centers and cell volumes + line = fuge.readline() + line = line.split() + num_cells = int(line[1]) + + cell_id = np.zeros(num_cells, 'int') + cell_coord = np.zeros((num_cells, 3), 'float') + cell_vol = np.zeros(num_cells, 'float') + + for cells in range(num_cells): + line = fuge.readline() + line = line.split() + cell_id[cells] = int(line.pop(0)) + line = [float(id) for id in line] + cell_vol[cells] = line.pop(3) + cell_coord[cells] = line + + print('--> Finished processing uge file\n') + + # loop through zone files + if zone_file == 'all': + zone_files = ['boundary_front_n.zone', 'boundary_back_s.zone', 'boundary_left_w.zone', 'boundary_right_e.zone', 'boundary_top.zone', 'boundary_bottom.zone'] + face_names = ['north', 'south', 'west', 'east', 'top', 'bottom'] + else: + if zone_file == '': + error = 'ERROR: Please provide boundary zone filename!\n' + sys.stderr.write(error) + sys.exit(1) + if face == '': + error = 'ERROR: Please provide face name among: top, bottom, north, south, east, west !\n' + sys.stderr.write(error) + sys.exit(1) + zone_files = [zone_file] + face_names = [face] + + for iface, zone_file in enumerate(zone_files): + face = face_names[iface] + # Ex filename + ex_file = zone_file.strip('zone') + 'ex' + + # Opening the input file + print('--> Opening zone file: ', zone_file) + with open(zone_file, 'r') as fzone: + print('--> Reading boundary node ids') + node_array = fzone.read() + node_array = node_array.split() + num_nodes = int(node_array[4]) + node_array = np.array(node_array[5:-1], dtype='int') + print('--> Finished reading zone file') + + Boundary_cell_area_array = np.zeros(num_nodes, 'float') + for i in range(num_nodes): + Boundary_cell_area_array[ + i] = boundary_cell_area # Fix the area to a large number + + print('--> Finished calculating boundary connections') + boundary_cell_coord = [ + cell_coord[cell_id[i - 1] - 1] for i in node_array + ] + epsilon = self.h * 10**-3 + + if (face == 'top'): + boundary_cell_coord = [[cell[0], cell[1], cell[2] + epsilon] + for cell in boundary_cell_coord] + elif (face == 'bottom'): + boundary_cell_coord = [[cell[0], cell[1], cell[2] - epsilon] + for cell in boundary_cell_coord] + elif (face == 'north'): + boundary_cell_coord = [[cell[0], cell[1] + epsilon, cell[2]] + for cell in boundary_cell_coord] + elif (face == 'south'): + boundary_cell_coord = [[cell[0], cell[1] - epsilon, cell[2]] + for cell in boundary_cell_coord] + elif (face == 'east'): + boundary_cell_coord = [[cell[0] + epsilon, cell[1], cell[2]] + for cell in boundary_cell_coord] + elif (face == 'west'): + boundary_cell_coord = [[cell[0] - epsilon, cell[1], cell[2]] + for cell in boundary_cell_coord] + elif (face == 'well'): + boundary_cell_coord = [[cell[0], cell[1], cell[2] + epsilon] + for cell in boundary_cell_coord] + elif (face == 'none'): + boundary_cell_coord = [[cell[0], cell[1], cell[2]] + for cell in boundary_cell_coord] + else: + error = 'ERROR: unknown face. Select one of: top, bottom, east, west, north, south.\n' + sys.stderr.write(error) + sys.exit(1) + ## Write out ex files + with open(ex_file, 'w') as f: + f.write('CONNECTIONS\t%i\n' % node_array.size) + for idx, cell in enumerate(boundary_cell_coord): + f.write( + f"{node_array[idx]}\t{cell[0]:.12e}\t{cell[1]:.12e}\t{cell[2]:.12e}\t{Boundary_cell_area_array[idx]:.12e}\n" + ) + + print( + f'--> Finished writing ex file {ex_file} corresponding to the zone file: {zone_file} \n' + ) + + print('--> Converting zone files to ex complete') + print('*' * 80) + print()
+ + +
+[docs] +def write_perms_and_correct_volumes_areas(self): + """ Write permeability values to perm_file, write aperture values to aper_file, and correct volume areas in uge_file + + Parameters + ---------- + self : object + DFN Class + + Returns + --------- + None + + Notes + ---------- + Calls executable correct_uge + """ + print('*' * 80) + print("--> Correcting UGE file: Starting") + if self.flow_solver != "PFLOTRAN": + error = "Error. Wrong flow solver requested\n" + sys.stderr.write(error) + sys.exit(1) + + print("--> Writing Perms and Correct Volume Areas") + if self.inp_file == '': + error = 'Error.: inp file must be specified!\n' + sys.stderr.write(error) + sys.exit(1) + + if self.uge_file == '': + error = 'Error. uge file must be specified!\n' + sys.stderr.write(error) + sys.exit(1) + + if self.perm_file == '' and self.perm_cell_file == '': + error = 'Error. perm file must be specified!\n' + sys.stderr.write(error) + sys.exit(1) + + if self.aper_file == '' and self.aper_cell_file == '': + error = 'ERROR: aperture file must be specified!\n' + sys.stderr.write(error) + sys.exit(1) + + t = time() + # Make input file for C UGE converter + with open("convert_uge_params.txt", "w") as fp: + fp.write(f"{self.inp_file}\n") + fp.write(f"{self.mat_file}\n") + fp.write(f"{self.uge_file}\n") + fp.write(f"{self.uge_file[:-4]}_vol_area.uge\n") + if self.cell_based_aperture: + fp.write(f"{self.aper_cell_file}\n") + fp.write("1\n") + else: + fp.write(f"{self.aper_file}\n") + fp.write("-1\n") + + ## dump aperture file + self.dump_aperture(self.aper_file, format='fehm') + ## execute convert uge C code + cmd = os.environ['CORRECT_UGE_EXE'] + ' convert_uge_params.txt' + print(f"\n>> {cmd}\n") + failure = subprocess.call(cmd, shell=True) + if failure > 0: + error = 'ERROR: UGE conversion failed\nExiting Program\n' + sys.stderr.write(error) + sys.exit(1) + elapsed = time() - t + print( + f'--> Time elapsed for UGE file conversion: {elapsed:0.3f} seconds\n') + + print("--> Correcting UGE file: Complete") + print('*' * 80) + print()
+ + + +def dump_h5_files(self): + """ Write permeability values to cell ids and permeability values to dfn_properties.h5 file for pflotran. + + Parameters + ---------- + self : object + DFN Class + + Returns + --------- + None + + Notes + ---------- + Hydraulic properties need to attached to the class prior to running this function. Use DFN.assign_hydraulic_properties() to do so. + """ + print('*' * 80) + print("--> Dumping h5 file") + filename = 'dfn_properties.h5' + print(f'--> Opening HDF5 File {filename}') + with h5py.File(filename, mode='w') as h5file: + print('--> Allocating cell index array') + print('--> Writing cell indices') + iarray = np.arange(1, self.num_nodes + 1) + dataset_name = 'Cell Ids' + h5dset = h5file.create_dataset(dataset_name, data=iarray) + print('--> Creating permeability array') + print('--> Note: This script assumes isotropic permeability') + if self.cell_based_aperture: + self.perm_cell = np.genfromtxt(self.perm_cell_file, skip_header = 1)[:,1] + else: + for i in range(self.num_nodes): + self.perm_cell[i] = self.perm[self.material_ids[i] - 1] + print('--> Writting Permeability') + dataset_name = 'Permeability' + h5dset = h5file.create_dataset(dataset_name, data=self.perm_cell) + + print("--> Done writting h5 file") + print('*' * 80) + print() + +
+[docs] +def pflotran(self, transient=False, restart=False, restart_file=''): + """ Run PFLOTRAN. Copy PFLOTRAN run file into working directory and run with ncpus + + Parameters + ---------- + self : object + DFN Class + transient : bool + Boolean if PFLOTRAN is running in transient mode + restart : bool + Boolean if PFLOTRAN is restarting from checkpoint + restart_file : string + Filename of restart file + + Returns + ---------- + None + + Notes + ---------- + Runs PFLOTRAN Executable, see http://www.pflotran.org/ for details on PFLOTRAN input cards + """ + if self.flow_solver != "PFLOTRAN": + error = "ERROR! Wrong flow solver requested\n" + sys.stderr.write(error) + sys.exit(1) + + try: + shutil.copy(os.path.abspath(self.dfnFlow_file), + os.path.abspath(os.getcwd())) + except: + error = "--> ERROR!! Unable to copy PFLOTRAN input file\n" + sys.stderr.write(error) + sys.exit(1) + + print("=" * 80) + print("--> Running PFLOTRAN") + + mpirun = os.environ['PETSC_DIR'] + '/' + os.environ[ + 'PETSC_ARCH'] + '/bin/mpirun' + + if not (os.path.isfile(mpirun) and os.access(mpirun, os.X_OK)): + # PETSc did not install MPI. Hopefully, the user has their own MPI. + mpirun = 'mpirun' + + cmd = mpirun + ' -np ' + str(self.ncpu) + \ + ' ' + os.environ['PFLOTRAN_EXE'] + ' -pflotranin ' + self.local_dfnFlow_file + + print(f"--> Running: {cmd}") + subprocess.call(cmd, shell=True) + + if restart: + try: + shutil.copy(os.path.abspath(restart_file), + os.path.abspath(os.getcwd())) + except: + error = "--> ERROR!! Unable to copy PFLOTRAN restart input file\n" + sys.stderr.write(error) + sys.exit(1) + + print("=" * 80) + print("--> Running PFLOTRAN") + cmd = os.environ['PETSC_DIR']+'/'+os.environ['PETSC_ARCH']+'/bin/mpirun -np ' + str(self.ncpu) + \ + ' ' + os.environ['PFLOTRAN_EXE'] + ' -pflotranin ' + ntpath.basename(restart_file) + print("Running: %s" % cmd) + subprocess.call(cmd, shell=True) + + print('=' * 80) + print("--> Running PFLOTRAN Complete") + print('=' * 80) + print("\n")
+ + + +
+[docs] +def pflotran_cleanup(self, index_start=0, index_finish=1, filename=''): + """pflotran_cleanup + Concatenate PFLOTRAN output files and then delete them + + Parameters + ----------- + self : object + DFN Class + index : int + If PFLOTRAN has multiple dumps use this to pick which dump is put into cellinfo.dat and darcyvel.dat + Returns + ---------- + None + + Notes + ---------- + Can be run in a loop over all pflotran dumps + """ + if self.flow_solver != "PFLOTRAN": + error = "ERROR! Wrong flow solver requested\n" + sys.stderr.write(error) + sys.exit(1) + + if filename == '': + filename = self.local_dfnFlow_file[:-3] + else: + filename = ntpath.basename(filename[:-3]) + + print('--> Processing PFLOTRAN output') + + for index in range(index_start, index_finish + 1): + cmd = 'cat ' + filename + '-cellinfo-%03d-rank*.dat > cellinfo_%03d.dat' % ( + index, index) + print("Running >> %s" % cmd) + subprocess.call(cmd, shell=True) + + cmd = 'cat ' + filename + '-darcyvel-%03d-rank*.dat > darcyvel_%03d.dat' % ( + index, index) + print(f"--> Running >> {cmd}") + subprocess.call(cmd, shell=True) + + #for fl in glob.glob(self.local_dfnFlow_file[:-3]+'-cellinfo-000-rank*.dat'): + # os.remove(fl) + #for fl in glob.glob(self.local_dfnFlow_file[:-3]+'-darcyvel-000-rank*.dat'): + # os.remove(fl) + + for fl in glob.glob(filename + '-cellinfo-%03d-rank*.dat' % index): + os.remove(fl) + for fl in glob.glob(filename + '-darcyvel-%03d-rank*.dat' % index): + os.remove(fl) + try: + os.symlink("darcyvel_%03d.dat" % index_finish, "darcyvel.dat") + except: + print("--> WARNING!!! Unable to create symlink for darcyvel.dat") + try: + os.symlink("cellinfo_%03d.dat" % index_finish, "cellinfo.dat") + except: + print("--> WARNING!!! Unable to create symlink for cellinfo.dat")
+ + + +
+[docs] +def parse_pflotran_vtk_python(self, grid_vtk_file=''): + """ Adds CELL_DATA to POINT_DATA in the VTK output from PFLOTRAN. + Parameters + ---------- + self : object + DFN Class + grid_vtk_file : string + Name of vtk file with mesh. Typically local_dfnFlow_file.vtk + + Returns + -------- + None + + Notes + -------- + If DFN class does not have a vtk file, inp2vtk_python is called + """ + print('--> Parsing PFLOTRAN output with Python') + + if self.flow_solver != "PFLOTRAN": + error = "ERROR! Wrong flow solver requested\n" + sys.stderr.write(error) + sys.exit(1) + + if grid_vtk_file: + self.vtk_file = grid_vtk_file + else: + self.inp2vtk_python() + + grid_file = self.vtk_file + + files = glob.glob('*-[0-9][0-9][0-9].vtk') + files.sort() + + with open(grid_file, 'r') as f: + grid = f.readlines()[3:] + + out_dir = 'parsed_vtk' + + for line in grid: + if 'POINTS' in line: + num_cells = line.strip(' ').split()[1] + + for file in files: + print(f"--> Processing file: {file}") + with open(file, 'r') as f: + pflotran_out = f.readlines()[4:] + pflotran_out = [ + w.replace('CELL_DATA', 'POINT_DATA ') for w in pflotran_out + ] + header = [ + '# vtk DataFile Version 2.0\n', 'PFLOTRAN output\n', 'ASCII\n' + ] + filename = out_dir + '/' + file + if not os.path.exists(os.path.dirname(filename)): + os.makedirs(os.path.dirname(filename)) + with open(filename, 'w') as f: + for line in header: + f.write(line) + for line in grid: + f.write(line) + f.write('\n') + f.write('\n') + if 'vel' in file: + f.write('POINT_DATA\t ' + num_cells + '\n') + for line in pflotran_out: + f.write(line) + os.remove(file) + print('--> Parsing PFLOTRAN output complete')
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/generation/generator.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/generation/generator.html new file mode 100644 index 000000000..c805de5e2 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/generation/generator.html @@ -0,0 +1,656 @@ + + + + + + pydfnworks.dfnGen.generation.generator — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for pydfnworks.dfnGen.generation.generator

+import os
+import sys
+import numpy as np
+import shutil
+from time import time
+import subprocess
+
+
+
+[docs] +def dfn_gen(self, output=True): + ''' Wrapper script the runs the dfnGen workflow: + 1) make_working_directory: Create a directory with name of job + 2) check_input: Check input parameters and create a clean version of the input file + 3) create_network: Create network. DFNGEN v2.0 is called and creates the network + 4) output_report: Generate a PDF summary of the DFN generation + 5) mesh_network: calls module dfnGen_meshing and runs LaGriT to mesh the DFN + + Parameters + ---------- + self : + DFN object + output : bool + If True, output pdf will be created. If False, no pdf is made + visual_mode : None + If the user wants to run in a different meshing mode from what is in params.txt, set visual_mode = True/False on command line to override meshing mode + + Returns + ------- + None + + Notes + ----- + Details of each portion of the routine are in those sections + + ''' + # Create Working directory + self.make_working_directory() + # Check input file + self.check_input() + # Create network + self.create_network() + if output: + self.output_report() + # Mesh Network + self.mesh_network() + print('=' * 80) + print('dfnGen Complete') + print('=' * 80)
+ + + +
+[docs] +def make_working_directory(self, delete=False): + ''' Make working directory for dfnWorks Simulation + + Parameters + ---------- + self : + DFN object + + delete : bool + If True, deletes the existing working directory. Default = False + + Returns + ------- + None + + Notes + ----- + If directory already exists, user is prompted if they want to overwrite and proceed. If not, program exits. + ''' + + if not delete: + try: + os.mkdir(self.jobname) + except OSError: + if os.path.isdir(self.jobname): + print('\nFolder ', self.jobname, ' exists') + keep = input('Do you want to delete it? [yes/no] \n') + if keep == 'yes' or keep == 'y': + print('Deleting', self.jobname) + shutil.rmtree(self.jobname) + print('Creating', self.jobname) + os.mkdir(self.jobname) + elif keep == 'no' or 'n': + error = "Not deleting folder. Exiting Program\n" + sys.stderr.write(error) + sys.exit(1) + else: + error = "Unknown Response. Exiting Program\n" + sys.stderr.write(error) + sys.exit(1) + else: + error = f"Unable to create working directory {self.jobname}\n. Please check the provided path.\nExiting\n" + sys.stderr.write(error) + sys.exit(1) + else: + if not os.path.isdir(self.jobname): + os.mkdir(self.jobname) + else: + try: + shutil.rmtree(self.jobname) + print('--> Creating ', self.jobname) + os.mkdir(self.jobname) + except: + error = "ERROR deleting and creating directory.\nExiting\n" + sys.stderr.write(error) + sys.exit(1) + + os.mkdir(self.jobname + '/dfnGen_output') + os.mkdir(self.jobname + '/dfnGen_output/radii') + os.mkdir(self.jobname + '/intersections') + os.mkdir(self.jobname + '/polys') + os.chdir(self.jobname) + + print(f"Current directory is now: {os.getcwd()}") + print(f"Jobname is {self.jobname}")
+ + + +
+[docs] +def create_network(self): + ''' Execute dfnGen + + Parameters + ---------- + self : + DFN object + + Returns + ------- + None + + Notes + ----- + After generation is complete, this script checks whether the generation of the fracture network failed or succeeded based on the existence of the file params.txt. + ''' + print('--> Running DFNGEN') + os.chdir(self.jobname) + cmd = os.environ[ + 'DFNGEN_EXE'] + ' ' + 'dfnGen_output/' + self.local_dfnGen_file[: + -4] + '_clean.dat' + ' ' + self.jobname + + print(f"Running:\n>>{cmd}") + subprocess.call(cmd, shell=True) + + if os.path.isfile("params.txt"): + self.gather_dfn_gen_output() + self.assign_hydraulic_properties() + print('-' * 80) + print("Generation Succeeded") + print('-' * 80) + else: + error = f"Error. Unable to find 'params.txt' in current directory {os.getcwd}.\n" + sys.stderr.write(error) + sys.exit(1)
+ + +def parse_params_file(self, quiet=False): + """ Reads params.txt file from DFNGen and parses information + + Parameters + --------- + quiet : bool + If True details are not printed to screen, if False they area + + Returns + ------- + None + + Notes + ----- + None + """ + if not quiet: + print("\n--> Parsing params.txt") + + fparams = open('params.txt', 'r') + # Line 1 is the number of polygons + self.num_frac = int(fparams.readline()) + #Line 2 is the h scale + self.h = float(fparams.readline()) + # Line 3 is the visualization mode: '1' is True, '0' is False. + self.visual_mode = int(fparams.readline()) + # line 4 dudded points + self.dudded_points = int(fparams.readline()) + + # Dict domain contains the length of the domain in x,y, and z + self.domain = {'x': 0, 'y': 0, 'z': 0} + #Line 5 is the x domain length + self.domain['x'] = (float(fparams.readline())) + + #Line 5 is the x domain length + self.domain['y'] = (float(fparams.readline())) + + #Line 5 is the x domain length + self.domain['z'] = (float(fparams.readline())) + self.r_fram = self.params['rFram']['value'] + + fparams.close() + + if not quiet: + print("--> Number of Fractures: %d" % self.num_frac) + print(f"--> h: {self.h:0.2e} m") + if self.visual_mode > 0: + self.visual_mode = True + print("--> Visual mode is on") + else: + self.visual_mode = False + print("--> Visual mode is off") + + print(f"--> Expected Number of dudded points: {self.dudded_points}") + print(f"--> X Domain Size {self.domain['x']} m") + print(f"--> Y Domain Size {self.domain['y']} m") + print(f"--> Z Domain Size {self.domain['z']} m") + + self.x_min = -0.5*self.domain['x'] + self.x_max = 0.5*self.domain['x'] + + self.y_min = -0.5*self.domain['y'] + self.y_max = 0.5*self.domain['y'] + + self.z_max = 0.5*self.domain['z'] + self.z_min = -0.5*self.domain['z'] + + print("--> Parsing params.txt complete\n") + + +def gather_dfn_gen_output(self): + """ Reads in information about fractures and add them to the DFN object. Information is taken from radii.dat, translations.dat, normal_vectors.dat, and surface_area_Final.dat files. Information for each fracture is stored in a dictionary created by create_fracture_dictionary() that includes the fracture id, radius, normal vector, center, family number, surface area, and if the fracture was removed due to being isolated + + Parameters + ----------- + None + + Returns + -------- + fractures : list + List of fracture dictionaries with information. + Notes + ------ + Both fractures in the final network and those removed due to being isolated are included in the list. + + """ + print("--> Parsing dfnWorks output and adding to object") + self.parse_params_file(quiet=False) + + ## load radii + data = np.genfromtxt('dfnGen_output/radii_Final.dat', skip_header=2) + ## populate radius array + self.radii = np.zeros((self.num_frac, 3)) + # First Column is x, second is y, 3rd is max + if self.num_frac == 1: + data = np.array([data]) + + self.radii[:, :2] = data[:, :2] + for i in range(self.num_frac): + self.radii[i, 2] = max(self.radii[i, 0], self.radii[i, 1]) + + # gather fracture families + self.families = data[:, 2].astype(int) + + ## load surface area + self.surface_area = np.genfromtxt('dfnGen_output/surface_area_Final.dat', skip_header=1) + ## load normal vectors + self.normal_vectors = np.genfromtxt('dfnGen_output/normal_vectors.dat') + # Get fracture centers + centers = [] + with open('dfnGen_output/translations.dat', "r") as fp: + fp.readline() # header + for i, line in enumerate(fp.readlines()): + if "R" not in line: + line = line.split() + centers.append( + [float(line[0]), + float(line[1]), + float(line[2])]) + self.centers = np.array(centers) + + # Grab Polygon information + self.poly_info = np.genfromtxt('poly_info.dat') + + # write polygon information to class + if self.store_polygon_data == True: + self.grab_polygon_data() + + ## create holder arrays for b, k, and T + self.aperture = np.zeros(self.num_frac) + self.perm = np.zeros(self.num_frac) + self.transmissivity = np.zeros(self.num_frac) + + # gather indexes for fracture families + self.family = [] + ## get number of families + self.num_families = int(max(self.families)) + for i in range(1, self.num_families + 1): + idx = np.where(self.families == i) + self.family.append(idx) + + # get fracture_info + self.fracture_info = np.genfromtxt('dfnGen_output/fracture_info.dat', skip_header = 1) + + # get intersection_list + self.intersection_list = np.genfromtxt('dfnGen_output/intersection_list.dat', skip_header = 1) + + # get boundary_files + self.back = read_boundaries('dfnGen_output/back.dat') + self.front = read_boundaries('dfnGen_output/front.dat') + self.left = read_boundaries('dfnGen_output/left.dat') + self.right = read_boundaries('dfnGen_output/right.dat') + self.top = read_boundaries('dfnGen_output/top.dat') + self.bottom = read_boundaries('dfnGen/bottom.dat') + +def read_boundaries(file_path): + '''Reads in boundary files, and corrects format is file is empty of length 1 + Parameters + ----------- + file_path : the path to boundary file + + Returns + -------- + array of values (or empty array if file is empty + + Notes + ------ + None + ''' + + if os.path.isfile(file_path) and os.path.getsize(file_path) > 0: + data = np.genfromtxt(file_path) + else: + data = np.array([]) + + try: + array_length = len(data) + except: + data = np.array([data]) + + return data + + +def assign_hydraulic_properties(self): + '''Assigns hydraulic properties for each familiy and user defined fractures + + Parameters + ----------- + self : DFN object + + Returns + -------- + None + + Notes + ------ + None + ''' + + print("--> Assign hydraulic properties: Starting ") + ### Assign variables for fracture families + print("--> Assign hydraulic properties to fracture families : Starting ") + for i in range(self.params['nFracFam']['value']): + hy_variable = self.fracture_families[i]['hydraulic_properties'][ + 'variable']['value'] + hy_function = self.fracture_families[i]['hydraulic_properties'][ + 'function']['value'] + hy_params = self.fracture_families[i]['hydraulic_properties'][ + 'params']['value'] + + if hy_variable is not None: + self.generate_hydraulic_values(hy_variable, + hy_function, + hy_params, + family_id=i + 1) + print("--> Assign hydraulic properties to fracture families : Complete ") + + ### Assign variables for user defined fractures and skip rejected fractures + ##Logic here, loop through user defined fractures + ## first check flag to insert + file_path = 'dfnGen_output/userFractureRejections.dat' + if os.path.isfile(file_path) and os.path.getsize(file_path) > 0: + try: + reject_fracs, frac_type = np.genfromtxt(file_path, delimiter = ',', skip_header = 1, unpack=True) + reject_fracs = np.array([reject_fracs]) #needed for case with one rejected fracture, genfromtxt reads in float otherwise + frac_type = np.array([frac_type]) + except: + print('--> No Rejected User Fractures, Ignore Following Warning.') + reject_fracs = np.array([]) + frac_type = np.array([]) + else: #if no fractures are rejected + print('--> No Rejected User Fractures, Ignore Following Warning.') + reject_fracs = np.array([]) + frac_type = np.array([]) + + rect_reject = reject_fracs[(frac_type == -2)] #integer corresponds to fracture type + ell_reject = reject_fracs[(frac_type == -1)] + poly_reject = reject_fracs[(frac_type == -3)] + + fracture_num = 1 #keep track of overall fracture number, and numbers for different types of fractures + frac_ell_num = 1 + frac_rect_num = 1 + frac_poly_num = 1 + + if self.params['insertUserRectanglesFirst']['value'] == 0: + print('--> Inserting User Ellipse Hydraulic Params First') + for i in range(len(self.user_ell_params)): + for j in range(self.user_ell_params[i]['nPolygons']): + if frac_ell_num not in ell_reject: + print(f'--> Inserting User Ell Hydraulic Params {fracture_num}') + hy_prop_type = self.user_ell_params[i]['hy_prop_type'] + value = self.user_ell_params[i][hy_prop_type][j] + print(f'{hy_prop_type} = {value}') + self.set_fracture_hydraulic_values(hy_prop_type, [fracture_num], + [value]) + fracture_num += 1 + + frac_ell_num += 1 + + for i in range(len(self.user_rect_params)): + for j in range(self.user_rect_params[i]['nPolygons']): + if frac_rect_num not in rect_reject: + print(f'--> Inserting User Rect Hydraulic Params {fracture_num}') + hy_prop_type = self.user_rect_params[i]['hy_prop_type'] + value = self.user_rect_params[i][hy_prop_type][j] + print(f'{hy_prop_type} = {value}') + self.set_fracture_hydraulic_values(hy_prop_type, [fracture_num], + [value]) + fracture_num += 1 + + frac_rect_num += 1 + + for i in range(len(self.user_poly_params)): + for j in range(self.user_poly_params[i]['nPolygons']): + if frac_poly_num not in poly_reject: + print(f'--> Inserting User Poly Hydraulic Params {fracture_num}') + hy_prop_type = self.user_poly_params[i]['hy_prop_type'] + value = self.user_poly_params[i][hy_prop_type][j] + print(f'{hy_prop_type} = {value}') + self.set_fracture_hydraulic_values(hy_prop_type, [fracture_num], + [value]) + fracture_num += 1 + + frac_poly_num += 1 + + else: + print('--> Inserting User Rectangle Hydraulic Params First') + for i in range(len(self.user_rect_params)): + for j in range(self.user_rect_params[i]['nPolygons']): + if frac_rect_num not in rect_reject: + print(f'--> Inserting User Rect Hydraulic Params {fracture_num}') + hy_prop_type = self.user_rect_params[i]['hy_prop_type'] + value = self.user_rect_params[i][hy_prop_type][j] + print(f'{hy_prop_type} = {value}') + self.set_fracture_hydraulic_values(hy_prop_type, [fracture_num], + [value]) + fracture_num += 1 + + frac_rect_num += 1 + + for i in range(len(self.user_ell_params)): + for j in range(self.user_ell_params[i]['nPolygons']): + if frac_ell_num not in ell_reject: + print(f'--> Inserting User Ell Hydraulic Params {fracture_num}') + hy_prop_type = self.user_ell_params[i]['hy_prop_type'] + value = self.user_ell_params[i][hy_prop_type][j] + print(f'{hy_prop_type} = {value}') + + self.set_fracture_hydraulic_values(hy_prop_type, [fracture_num], + [value]) + fracture_num += 1 + + frac_ell_num += 1 + + for i in range(len(self.user_poly_params)): + for j in range(self.user_poly_params[i]['nPolygons']): + if frac_poly_num not in poly_reject: + print(f'--> Inserting User Poly Hydraulic Params {fracture_num}') + hy_prop_type = self.user_poly_params[i]['hy_prop_type'] + value = self.user_poly_params[i][hy_prop_type][j] + print(f'{hy_prop_type} = {value}') + self.set_fracture_hydraulic_values(hy_prop_type, [fracture_num], + [value]) + fracture_num += 1 + + frac_poly_num += 1 + + # self.dump_hydraulic_values() + print("--> Assign hydraulic properties: Complete ") + +
+[docs] +def grab_polygon_data(self): + '''If flag self.store_polygon_data is set to True, the information stored in polygon.dat is written to a dictionary self.polygons. + To access the points that define an individual polygon, call self.polygons[f'poly{i}'] where i is a number between 1 and the number of defined polygons. This returns an array of coordinates in the format np.array([x1,y1,z1],[x2,y2,z2],...[xn,yn,zn]) + + Parameters + ----------- + self : DFN object + + Returns + -------- + None + + Notes + ------ + None + ''' + + print("--> Loading Polygon information onto DFN object") + self.polygons = {} + + polygon_data = np.genfromtxt('dfnGen_output/polygons.dat', dtype = str, delimiter = 'dummy', skip_header = 1) #weird format, so read data in as strings + + if self.num_frac == 1: + polygon_data = np.array([polygon_data]) + + + for i in range(len(polygon_data)): + poly_dat = polygon_data[i] #read in data for one polygon + poly_dat = poly_dat.replace('}', '') #get rid of weird characters + poly_dat = poly_dat.replace('{', '') + poly_dat = poly_dat.replace(',', '') + poly_dat = poly_dat.split() #convert string to list, and then array + poly_dat = np.array(poly_dat) + poly_dat = poly_dat.astype(float) + poly = [] + for j in range(int(poly_dat[0])): #loop through and reformat individual coordinates + poly.append(poly_dat[3*j+1:3*j+4]) + poly = np.array(poly) + self.polygons[f'fracture-{i+1}'] = poly #store in dictionary + print('--> Data from polygons.dat stored on class in self.polygons\n')
+ + +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/generation/input_checking/check_input.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/generation/input_checking/check_input.html new file mode 100644 index 000000000..14fcd21bb --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/generation/input_checking/check_input.html @@ -0,0 +1,229 @@ + + + + + + pydfnworks.dfnGen.generation.input_checking.check_input — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for pydfnworks.dfnGen.generation.input_checking.check_input

+import os
+import shutil
+import sys
+
+#pydfnworks modules
+import pydfnworks.dfnGen.generation.input_checking.helper_functions as hf
+from pydfnworks.dfnGen.generation.input_checking.parsing import parse_input
+from pydfnworks.dfnGen.generation.input_checking.verifications import verify_params
+from pydfnworks.dfnGen.generation.input_checking.write_input_file import dump_params
+from pydfnworks.dfnGen.generation.input_checking.add_fracture_family_to_params import write_fracture_families
+
+
+
+
+
+
+
+[docs] +def check_input(self, from_file=False): + """ Checks input file for DFNGen to make sure all necessary parameters are defined. Then writes out a "clean" version of the input file + + Input Format Requirements: + * Each parameter must be defined on its own line (separate by newline) + * A parameter (key) MUST be separated from its value by a colon ':' (ie. --> key: value) + * Values may also be placed on lines after the 'key' + * Comment Format: On a line containing // or / ``*``, nothing after ``*`` / or // will be processed but text before a comment will be processed + + Parameters + ------------ + self : DFN Class Object + + Returns + --------- + None + + Notes + ----- + There are warnings and errors raised in this function. Warning will let you continue while errors will stop the run. Continue past warnings are your own risk. + + From File feature is no longer maintained. Functions should be removed in the near future. + """ + print() + print('=' * 80) + print("Checking Input File\n") + ## Needs to be a logic fork here for using input file + from_file = from_file #added call to function creat_dfn to set flag, default is false + if from_file: + # Copy input file + if os.path.isfile(self.dfnGen_file): + try: + print(f"--> Copying input file: {self.dfnGen_file}") + shutil.copy(self.dfnGen_file, self.jobname) + print("--> Copying input file successful") + except: + error = f"Unable to copy dfnGen input file to working directory \n{self.dfnGen_file}\n Exiting" + sys.stderr.write(error) + sys.exit(1) + else: + error = f"Input file \n{self.dfnGen_file} not found\n Exiting" + sys.stderr.write(error) + sys.exit(1) + input_file = self.local_dfnGen_file + output_file = "dfnGen_output/" + self.local_dfnGen_file[:-4] + '_clean.dat' + print(f"--> Reading input file: {input_file}") + self.params = parse_input(input_file) + + else: + output_file = "dfnGen_output/" + self.local_dfnGen_file[:-4] + '_clean.dat' + self.params = self.write_fracture_families() + self.write_user_fractures_to_file() + print(f"--> Clean output file name: {output_file}") + verify_params(self.params) + dump_params(self.params, output_file) + print("\nChecking Input File Complete") + print('=' * 80) + print()
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/generation/input_checking/fracture_family.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/generation/input_checking/fracture_family.html new file mode 100644 index 000000000..e549be22d --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/generation/input_checking/fracture_family.html @@ -0,0 +1,586 @@ + + + + + + pydfnworks.dfnGen.generation.input_checking.fracture_family — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for pydfnworks.dfnGen.generation.input_checking.fracture_family

+import sys
+
+
+def fracture_family_dictionary():
+    """Creates a fracture family dictionary
+    
+    Parameters
+    --------------
+        None
+
+    Returns
+    --------
+        family : dictionary
+            fracture family dictionary for specified family
+            
+    Notes
+    ---------
+        See https://dfnworks.lanl.gov/dfngen.html#domain-parameters for more 
+        information about parameters in this dictionary
+    """
+
+    family = {
+        'number': {
+            'type': int,
+            'value': None,
+            'description': 'ID number for the fracture family'
+        },
+        'probability': {
+            'type':
+            float,
+            'value':
+            None,
+            'description':
+            'Probabiliy of occurence for the family of of stochastically generated fractures'
+        },
+        'type': {
+            'type':
+            bool,
+            'value': {
+                'rect': False,
+                'ellipse': False
+            },
+            'description':
+            'Specifies whether the fracture family consists of rectangular or elliptical fractures'
+        },
+        'layer': {
+            'type': int,
+            'value': 0,
+            'description': 'Assign family to a layer in the domain'
+        },
+        'region': {
+            'type': int,
+            'value': 0,
+            'description': 'Assign family to a region in the domain'
+        },
+        'p32': {
+            'type': float,
+            'value': None,
+            'description': 'Target fracture intensity'
+        },
+        'aspect': {
+            'type': float,
+            'value': 1,
+            'description': 'Aspect ratio of the fractures'
+        },
+        'number_of_points': {
+            'type':
+            int,
+            'value':
+            None,
+            'description':
+            'Number of vertices defining the boundary of each elliptical fracture'
+        },
+        'beta_distribution': {
+            'type':
+            bool,
+            'value':
+            False,
+            'description':
+            'Prescribe a rotation around each fractures normal vector, with the fracture centered on the x-y plane at the origin\nFalse:Uniform distribution on [0,2pi)\nTrue:Constant rotation specified by beta'
+        },
+        'beta': {
+            'type':
+            float,
+            'value':
+            None,
+            'description':
+            'Value for constant angle of rotation around the normal vector'
+        },
+        #fisher distribution
+        'fisher': {
+            'type':
+            float,
+            'value': {
+                'theta': None,
+                'phi': None,
+                'strike': None,
+                'dip': None,
+                'trend': None,
+                'plunge': None,
+                'kappa': None
+            },
+            'description':
+            '3 parameters theta, phi, and kappa for fisher distribution'
+        },
+        'distribution': {
+            'type': bool,
+            'value': {
+                'tpl': False,
+                'log_normal': False,
+                'exp': False,
+                'constant': False
+            },
+            'description':
+            'Type of distibution fracture radii are sampled from'
+        },
+        'tpl': {
+            'type': float,
+            'value': {
+                'alpha': None
+            },
+            'description': 'Parameter for truncated power-law distibution'
+        },
+        'log_normal': {
+            'type': float,
+            'value': {
+                'mean': None,
+                'std': None
+            },
+            'description': 'Parameters for log normal distribution'
+        },
+        'exp': {
+            'type': float,
+            'value': {
+                'mean': None
+            },
+            'description': 'Parameter for exponential distribution'
+        },
+        'constant': {
+            'type': float,
+            'value': None,
+            'description': 'Constant sized fracture family radius'
+        },
+        'min_radius': {
+            'type': float,
+            'value': None,
+            'description': 'Minimum radius created by distribution'
+        },
+        'max_radius': {
+            'type': float,
+            'value': None,
+            'description': 'Maximum radius created by distribution'
+        },
+        'hydraulic_properties': {
+            'variable': {
+                'type':
+                str,
+                'value':
+                None,
+                'description':
+                ' Acceptable values are aperture, permeability, and transmissivity'
+            },
+            'function': {
+                'type':
+                str,
+                'value':
+                None,
+                'description':
+                'Acceptable values or correlated, semi-correlated, constant, and log-normal'
+            },
+            'params': {
+                'type':
+                dict,
+                'value':
+                None,
+                'description':
+                'if correlated {"alpha":float, "beta":float},\nif semi-correlated {"alpha":float, "beta":float, "sigma":float},\nif constant {"mu":float},\nif log-normal {"mu":float,"sigma":float}'
+            }
+        }
+    }
+    return family
+
+
+
+
+
+
+
+[docs] +def add_fracture_family(self, + shape, + distribution, + kappa, + family_number=None, + probability=None, + p32=None, + layer=0, + region=0, + number_of_points=8, + aspect=1, + beta_distribution=0, + beta=0, + theta=None, + phi=None, + strike=None, + dip=None, + trend=None, + plunge=None, + alpha=None, + log_mean=None, + log_std=None, + exp_mean=None, + constant=None, + min_radius=None, + max_radius=None, + hy_variable=None, + hy_function=None, + hy_params=None): + """Generates a fracture family + + Parameters + -------------- + self : DFN object + + shape : 'rect' or 'ell' deines the fracture family shape + + distribution : 'tpl', 'log_normal', 'exp', or 'constant' defines the sample distribution for the fracture radius + + kappa : concentration param of the von Mises-Fisher distribution + + family_number : fracutre family id. default = None + + probability : probabily of a fracture belonging to this family. default = None. use if stopCondition = 0 + + p32 : fracture intensity for the family. default = None. use if stopCondition = 1 + layer : assigns fracture family to a layer in the domain. default = 0 + + region : assigns fracture family to a region in the domain. default = 0 + + number_of_points : specifies the number of vertices defining th eboundary of each fracture. default = 8 + + aspect : the aspect ratio of the fractures. default = 1 + + beta_distribution : 0 (uniform distribtuion [0,2pi) or 1 (constant rotation specfied by ebeta) rotation of each fractures normal vector. default 0 + + beta : angle fo constant rotation. use if beta_distribution = 1. default = 0 + + theta : use if orientationOption = 0 (default). default = None + + phi : use if orientationOption = 0 (default). default = None + + trend : use if orientationOption = 1. default = None + + plunge : use if orientationOption = 1. default = None + + dip : use if orientationOption = 2. default = None + + strike : use if orientationOption = 2. default = None + + alpha : parameter for 'tpl'. default = None + + log_mean : parameter for 'log_normal'. default = None + + log_std : parameter for 'log_normal'. default = None + + exp_mean : parameter for 'exp'. default = None + + constant : parameter for 'constant'. default = None + + min_radius : minimum fracture radius for 'tpl' 'log_normal' or 'exp'. default = None + + max_radius : maximum fracture radius for 'tpl' 'log_normal' or 'exp'. default = None + + hy_variable : hydraulic variable to assign values to. options are 'aperture', 'permeability', 'transmissivity', + + hy_function : relationship between hydraulic variable and fracture radius. options are 'correlated', 'semi-correlated', 'constant', 'log-normal' + + hy_params : parameters for the hydraulic function. see next lines for syntax and options + if 'correlated' --> {"alpha":value, "beta:value} + if 'semi-correlated' --> {"alpha":value, "beta":value, "sigma":value} + if 'constant' --> {"mu":value} + if 'log-normal' --> {"mu":value, "sigma":value} + + Returns + -------- + Populated fracture family dictionary for specified family + + Notes + --------- + See https://dfnworks.lanl.gov/dfngen.html#domain-parameters for more + information about parameters + """ + + print("--> Adding new facture family") + + family = fracture_family_dictionary() + if shape == "rect": + family['type']['value']['rect'] = True + family['number_of_points']['value'] = 4 + elif shape == "ell": + family['type']['value']['ellipse'] = True + family['number_of_points']['value'] = number_of_points + else: + error = f"Unknown Fracture Type {shape}. Acceptable values are rect & ell. Exiting.\n" + sys.stderr.write(error) + sys.exit(1) + + family['layer']['value'] = layer + family['region']['value'] = region + + if p32: + family['p32']['value'] = p32 + family['probability']['value'] = p32 + elif probability: + family['probability']['value'] = probability + else: + error = f"A value for p32 or probability must be provided. Exiting.\n" + sys.stderr.write(error) + sys.exit(1) + + family['aspect']['value'] = aspect + + ## Orienation + family['beta_distribution']['value'] = beta_distribution + family['beta']['value'] = beta + family['fisher']['value']['theta'] = theta + family['fisher']['value']['phi'] = phi + family['fisher']['value']['strike'] = strike + family['fisher']['value']['dip'] = dip + family['fisher']['value']['trend'] = trend + family['fisher']['value']['plunge'] = plunge + family['fisher']['value']['kappa'] = kappa + + ## Set and check orientation option + # note orientationOption = 0 --> theta/phi + # orientationOption = 1 --> trend/plunge + # orientationOption = 2 --> stirke/dip + if theta != None and phi != None: + if self.params['orientationOption']['value'] == None: + print('Setting orientationOption = 0 (theta/phi)') + self.params['orientationOption']['value'] = 0 + if self.params['orientationOption']['value'] != 0: + error = f"0Each family must have only one of the pairs of parameters strike/dip, theta/phi or trend/plunge defined. Each family must have the same pair of parameters defined. \n" + sys.stderr.write(error) + sys.exit(1) + + if trend != None and plunge != None: + if self.params['orientationOption']['value'] == None: + print('Setting orientationOption = 1 (trend/plunge)') + self.params['orientationOption']['value'] = 1 + if self.params['orientationOption']['value'] != 1: + error = f"1Each family must have only one of the pairs of parameters strike/dip, theta/phi or trend/plunge defined. Each family must have the same pair of parameters defined. \n" + sys.stderr.write(error) + sys.exit(1) + + if strike != None and dip != None: + if self.params['orientationOption']['value'] == None: + print('Setting orientationOption = 2 (strike/dip)') + self.params['orientationOption']['value'] = 2 + if self.params['orientationOption']['value'] != 2: + error = f"2Each family must have only one of the pairs of parameters strike/dip, theta/phi or trend/plunge defined. Each family must have the same pair of parameters defined. \n" + sys.stderr.write(error) + sys.exit(1) + + ## Radius Distribution + if distribution == "tpl": + family['distribution']['value']['tpl'] = True + if alpha != None: + family['tpl']['value']['alpha'] = alpha + else: + error = f"Error. A value for alpha must be provided if family is tpl distribution. Exiting.\n" + sys.stderr.write(error) + sys.exit(1) + elif distribution == "log_normal": + family['distribution']['value']['log_normal'] = True + if log_mean != None: + family['log_normal']['value']['mean'] = log_mean + else: + error = f"Error. A value for log_mean must be provided if family is log_normal distribution. Exiting. \n" + sys.stderr.write(error) + sys.exit(1) + if log_std != None: + family['log_normal']['value']['std'] = log_std + else: + error = f"Error. A value for log_std must be provided if family is log_normal distribution. Exiting. \n" + sys.stderr.write(error) + sys.exit(1) + + elif distribution == "exp": + family['distribution']['value']['exp'] = True + if exp_mean != None: + family['exp']['value']['mean'] = exp_mean + else: + error = f"Error. A value for exp_mean must be provided if family is exp distribution. Exiting. \n" + sys.stderr.write(error) + sys.exit(1) + elif distribution == "constant": + family['distribution']['value']['constant'] = True + if constant != None: + family['constant']['value'] = constant + else: + error = f"Error. A value for constant must be provided if family is constant distribution. Exiting. \n" + sys.stderr.write(error) + sys.exit(1) + else: + error = f"Error. Unknown Fracture Distribution {distribution}. Acceptable values are 'tpl', 'exp', 'log_normal', & 'constant'. Exiting.\n" + sys.stderr.write(error) + sys.exit(1) + + if distribution != "constant": + if not min_radius or not max_radius: + error = f"Error. Minimum and Maximum radius must be provided unless using constant distribution. Exiting.\n" + sys.stderr.write(error) + sys.exit(1) + + family['min_radius']['value'] = min_radius + family['max_radius']['value'] = max_radius + + if family_number: + family['number']['value'] = family_number + else: + family_number = len(self.fracture_families) + 1 + + family['hydraulic_properties']['variable']['value'] = hy_variable + family['hydraulic_properties']['function']['value'] = hy_function + family['hydraulic_properties']['params']['value'] = hy_params + ##Do we need exceptions? it will be checked in dfnflow + + self.fracture_families.append(family) + self.print_family_information(family_number)
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/generation/input_checking/user_defined_fracture_functions.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/generation/input_checking/user_defined_fracture_functions.html new file mode 100644 index 000000000..8d431d8b2 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/generation/input_checking/user_defined_fracture_functions.html @@ -0,0 +1,747 @@ + + + + + + pydfnworks.dfnGen.generation.input_checking.user_defined_fracture_functions — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for pydfnworks.dfnGen.generation.input_checking.user_defined_fracture_functions

+import sys
+import os
+from numpy import pi
+
+from pydfnworks.dfnGen.generation.input_checking.helper_functions import print_error, print_warning
+
+def check_angle_option(angle_option, array):
+    for val in array:
+        if angle_option == "radian":
+            if val > 2 * pi:
+                print_warning(
+                    "Value greater than 2 PI, angle option of radians has been selected"
+                )
+        elif angle_option == "degree":
+            if val > 360:
+                print_warning(
+                    "Value greater than 2 PI, angle option of radians has been selected"
+                )
+
+
+
+
+
+
+
+[docs] +def add_user_fract_from_file(self, + filename, + shape, + nPolygons, + by_coord=False, + aperture=None, + transmissivity=None, + permeability=None): + """ Sets up paths for fractures defined in user input file. When inserting user fractures from file, hydraulic properties must be provided as a list of length nPolygons (number of fractures defined in the file) + + Parameters + ---------------- + filename : string + path to source file + + shape: string + The shape of the fracture options are 'rect', 'ell', and 'poly' - Required + + by_coord : boolean + True / False of file format for coordinate or general input + + nPolygons : int + The number of polygons specified in the file + + permeability : list or array + Permeabilities of the fractures + + transmissivity : list or array + Fracture Tramsmissivities + + aperture : list or array + Hydraulic apertures of the fracture + + Returns + --------------- + None + + Notes + -------------- + Does not write the file, only sets up paths + ~/src/dfnworks-aidan/pydfnworks/pydfnworks/ + """ + fracture_dictionary = {"shape": shape, "filename": filename} + + hy_prop_type = determine_hy_prop_type(aperture, transmissivity, + permeability) + fracture_dictionary['aperture'] = aperture + fracture_dictionary['transmissivity'] = transmissivity + fracture_dictionary['permeability'] = permeability + fracture_dictionary['hy_prop_type'] = hy_prop_type + fracture_dictionary['nPolygons'] = nPolygons + + + if aperture is not None: + if len(aperture) != nPolygons: + print_error("Error. aperture list for user fractures from file is not the same length as nPolygons, please check input for add_user_fract_from_file\n") + if transmissivity is not None: + if len(transmissivity) != nPolygons: + print_error("Error. transmissivity list for user fractures from file is not the same length as nPolygons, please check input for add_user_fract_from_file\n") + if permeability is not None: + if len(permeability) != nPolygons: + print_error("Error. aperture list for user fractures from file is not the same length as nPolygons, please check input for add_user_fract_from_file\n") + + + if shape == 'rect': + self.params['RectByCoord_Input_File_Path']['value'] = filename + if by_coord: + self.params['userRectByCoord']['value'] = True + else: + self.params['userRectanglesOnOff']['value'] = True + self.user_rect_params.append(fracture_dictionary) + frac_number = len(self.user_rect_params) + self.print_user_fracture_information('rect', frac_number - 1) + + elif shape == 'ell': + self.params['EllByCoord_Input_File_Path']['value'] = filename + if by_coord: + self.params['userEllByCoord']['value'] = True + else: + self.params['userEllipsesOnOff']['value'] = True + self.user_ell_params.append(fracture_dictionary) + frac_number = len(self.user_ell_params) + self.print_user_fracture_information('ell', frac_number - 1) + elif shape == 'poly': + # user polygon + self.params['userPolygonByCoord']['value'] = True + self.params['PolygonByCoord_Input_File_Path']['value'] = filename + self.user_poly_params.append(fracture_dictionary) + self.print_user_fracture_information('poly') + else: + print_error( + "Error.user fracture shape is not specified correctly, options are 'rect', 'ell', or 'poly'\n" + )
+ + + +
+[docs] +def add_user_fract(self, + shape, + radii, + translation, + filename=None, + aspect_ratio=1, + beta=0, + angle_option='degree', + orientation_option='normal', + normal_vector=None, + trend_plunge=None, + dip_strike=None, + number_of_vertices=None, + permeability=None, + transmissivity=None, + aperture=None): + """ + Specifies user defined fracture parameters for the DFN. + + Parameters + ------------- + shape: string + The desired shape of the fracture options are 'rect', 'ell', and 'poly' - Required + + radii : float + 1/2 size of the fracture in meters - Required + + translation : list of floats [3] + Fracture center + + filename: string + The name of the user defined fracture file. Default is user_defined_{shape}.dat + + aspect_ratio : float + Fracture aspect ratio + + beta : float + Rotation angle around center of the fracture + + angle_option : string + Angle option 'degree' or 'radian'. Default is degree + + orientation_option : string + Choice of fracture orienation 'normal', 'trend_plunge', 'dip_strike' + + normal_vector : list [3] + normal vector of the fracture + + trend_plunge : list [2] + trend and plunge of the fracture + + dip_strike : list [2] + dip and strike of the fracture + + number_of_vertices : int + Number of vertices on the fracture boundary. + + permeability : float + Permeability of the fracture + + transmissivity : float + Fracture Tramsmissivity + + aperture : float + Hydraulic aperture of the fracture + + Returns + --------- + None - fracture dictionaries are attached to the DFN object + + Notes + ------- + Please be aware, the user fracture files can only be automatically written for + ellipses and rectangles not specified by coordinate. + + See + + https://dfnworks.lanl.gov/dfngen.html#user-defined-fracture-generation-parameters + + for additional information + + """ + + # if specifying details in the python driver file. + fracture_dictionary = {"shape": shape} + fracture_dictionary['nPolygons'] = 1 + # Check input parameters + if filename: + fracture_dictionary['filename'] = filename + else: + filename = self.jobname + f"/dfnGen_output/user_defined_{shape}.dat" + fracture_dictionary['filename'] = filename + + # Check radius is positive. + if radii > 0: + fracture_dictionary['Radii:'] = radii + else: + print_error( + f"Error. Fracture radius must be positive. Value provided {radii}. Exiting." + ) + + # Check Aspect Ratio is positive + if aspect_ratio > 0: + fracture_dictionary['Aspect_Ratio:'] = aspect_ratio + else: + print_error( + f"Error. Aspect Ratio must be positive. Value provided {aspect_ratio}. Exiting." + ) + + ## check beta Rotation in non-negative. + if beta >= 0: + fracture_dictionary['Beta:'] = beta + else: + print_error( + f"Error. Beta rotation must be non-negative (>0). Value provided {beta}. Exiting." + ) + + # Check Angle options + angle_options = ['radian', 'degree'] + if angle_option in angle_options: + fracture_dictionary['AngleOption:'] = angle_option + else: + print_error( + f"Error. Unknown angle_option value provided: {angle_option}. Acceptable values are 'radian', 'degree'.\nExiting." + ) + + if len(translation) == 3: + fracture_dictionary['Translation:'] = translation + else: + print_error( + f"Error. Fracture Translation (center) must have 3 elements, only {len(translation)} provided.\nValue provided: {translation}. Exiting" + ) + + ## Check orienations and consistency + if orientation_option == 'normal': + fracture_dictionary['userOrientationOption:'] = 0 + if normal_vector: + fracture_dictionary['Normal:'] = normal_vector + else: + print_error( + "Error. Requested user fracture orienation 0, but normal vector was not provided. exiting." + ) + if len(normal_vector) != 3: + print_error( + f"Error. Normal vector must have 3 elements, only {len(normal_vector)} provided.\nNormal: {normal_vector}. Exiting" + ) + + elif orientation_option == 'trend_plunge': + fracture_dictionary['userOrientationOption:'] = 1 + if trend_plunge: + fracture_dictionary['Trend_Plunge:'] = trend_plunge + else: + print_error( + "Error. Requested user fracture orienation trend_plunge, but trend_plunge was not provided. exiting." + ) + + if len(trend_plunge) != 2: + print_error( + f"Error. Trend/Plunge must have 2 elements, only {len(trend_plunge)} provided.\trend_plunge: {trend_plunge}. Exiting" + ) + + # Check is angles make sense given radians or degrees + print("--> Checking trend_plunge angles") + check_angle_option(angle_option, trend_plunge) + + elif orientation_option == 'dip_strike': + fracture_dictionary['userOrientationOption:'] = 2 + if dip_strike: + fracture_dictionary['Dip_Strike:'] = dip_strike + else: + print_error( + "Error. Requested user fracture orienation dip_strike, but dip_strike was not provided. exiting." + ) + if len(dip_strike) != 2: + print_error( + f"Error. Dip/Strike must have 2 elements, only {len(dip_strike)} provided.\trend_plunge: {dip_strike}. Exiting" + ) + else: + print_error( + f"Error. Unknown orientation_option provided. Value: {orientation_option}. Options are 'normal', 'trend_plunge', and 'dip_strike'. Exiting" + ) + + # Check is angles make sense given radians or degrees + print("--> Checking dip_strike angles") + check_angle_option(angle_option, dip_strike) + + # hydraulic properties + hy_prop_type = determine_hy_prop_type(aperture, transmissivity, + permeability) + fracture_dictionary['aperture'] = [aperture] + fracture_dictionary['transmissivity'] = [transmissivity] + fracture_dictionary['permeability'] = [permeability] + fracture_dictionary['hy_prop_type'] = hy_prop_type + + ## Logic for i/o + if shape == 'rect': + self.params['userRectanglesOnOff']['value'] = True + self.params['UserRect_Input_File_Path']['value'] = fracture_dictionary[ + 'filename'] + self.user_rect_params.append(fracture_dictionary) + frac_number = len(self.user_rect_params) + self.print_user_fracture_information('rect', frac_number - 1) + + elif shape == 'ell': + if number_of_vertices > 2: + fracture_dictionary['Number_of_Vertices:'] = number_of_vertices + else: + print_error( + f"Error. number_of_vertices must be greater than 2. VAlue provided: {number_of_vertices}. Exiting." + ) + + self.params['userEllipsesOnOff']['value'] = True + self.params['UserEll_Input_File_Path']['value'] = fracture_dictionary[ + 'filename'] + + self.user_ell_params.append(fracture_dictionary) + frac_number = len(self.user_ell_params) + self.print_user_fracture_information('ell', frac_number - 1)
+ + + +def write_user_fractures_to_file(self): + """Writes the user defined fracutres to a file if file is not already specified + + Parameters + ------------ + self : DFN object + + Returns + --------- + None + + Notes + ------- + None + """ + + n_rects = len(self.user_rect_params) + n_ells = len(self.user_ell_params) + + if n_ells > 0: + print( + f"--> Writing user defined ellispes to file {self.params['UserEll_Input_File_Path']['value']}" + ) + with open(self.params['UserEll_Input_File_Path']['value'], + 'w+') as ell_file: + ell_file.write(f'nUserEll: {n_ells} \n \n') + orientation_option = self.user_ell_params[0][ + 'userOrientationOption:'] + for key in self.user_ell_params[0].keys(): + if key == 'userOrientationOption:': + value = self.user_ell_params[0][key] + ell_file.write(f'{key} {value} \n \n') + elif key == 'Normal:': + if orientation_option == 0: + ell_file.write(f'{key} \n') + for j in range(n_ells): + value = self.user_ell_params[j][key] + if value is not None: + ell_file.write(f'{value} \n') + else: + error = "user orientation option not specified correctly \n0:'normal'\n1:'trend_plunge'\n2:'dip_strike'\n" + sys.stderr.write(error) + sys.exit(1) + + ell_file.write('\n') + + else: + continue + + elif key == 'Trend_Plunge:': + + if orientation_option == 1: + ell_file.write(f'{key} \n') + for j in range(n_ells): + value = self.user_ell_params[j][key] + if value is not None: + ell_file.write(f'{value} \n') + else: + error = "user orientation option not specified correctly \n0:'normal'\n1:'trend_plunge'\n2:'dip_strike'\n" + sys.stderr.write(error) + sys.exit(1) + + ell_file.write('\n') + + else: + continue + + elif key == 'Dip_Strike:': + + if orientation_option == 2: + ell_file.write(f'{key} \n') + for j in range(n_ells): + value = self.user_ell_params[j][key] + if value is not None: + ell_file.write(f'{value} \n') + else: + error = "user orientation option not specified correctly \n0:'normal'\n1:'trend_plunge'\n2:'dip_strike'\n" + sys.stderr.write(error) + sys.exit(1) + + ell_file.write('\n') + + else: + continue + + elif key == 'filename' or key == 'shape': + continue + else: + + ell_file.write(f'{key} \n') + for j in range(n_ells): + value = self.user_ell_params[j][key] + ell_file.write(f'{value} \n') + ell_file.write('\n') + + if n_rects > 0: + + print( + f"--> Writing user defined rectangles to file {self.params['UserRect_Input_File_Path']['value']}" + ) + with open(self.params['UserRect_Input_File_Path']['value'], + 'w+') as rect_file: + + rect_file.write(f'nUserRect: {n_rects} \n \n') + + orientation_option = self.user_rect_params[0][ + 'userOrientationOption:'] + + for key in self.user_rect_params[0].keys(): + + if key == 'userOrientationOption:': + + value = self.user_rect_params[0][key] + rect_file.write(f'{key} {value} \n \n') + + elif key == 'Normal:': + + if orientation_option == 0: + rect_file.write(f'{key} \n') + for j in range(n_rects): + value = self.user_rect_params[j][key] + if value is not None: + rect_file.write(f'{value} \n') + else: + error = "user orientation option not specified correctly \n0:'Normal'\n1:'Trend_Plunge'\n2:Dip_Strike'" + sys.stderr.write(error) + sys.exit(1) + + rect_file.write('\n') + + else: + continue + + elif key == 'Trend_Plunge:': + + if orientation_option == 1: + rect_file.write(f'{key} \n') + for j in range(n_rects): + value = self.user_rect_params[j][key] + if value is not None: + rect_file.write(f'{value} \n') + else: + error = "user orientation option not specified correctly \n0:'Normal'\n1:'Trend_Plunge'\n2:Dip_Strike'" + sys.stderr.write(error) + sys.exit(1) + + rect_file.write('\n') + + else: + continue + + elif key == 'Dip_Strike:': + + if orientation_option == 2: + rect_file.write(f'{key} \n') + for j in range(n_rects): + value = self.user_rect_params[j][key] + if value is not None: + rect_file.write(f'{value} \n') + else: + error = "user orientation option not specified correctly \n0:'Normal'\n1:'Trend_Plunge'\n2:Dip_Strike'" + sys.stderr.write(error) + sys.exit(1) + + rect_file.write('\n') + + else: + continue + + elif key == 'filename': + continue + elif key == 'shape': + continue + + else: + + rect_file.write(f'{key} \n') + for j in range(n_rects): + value = self.user_rect_params[j][key] + rect_file.write(f'{value} \n') + rect_file.write('\n') + + +def determine_hy_prop_type(aperture, transmissivity, permeability): + """Determines the type of user defined hydraulic property based on user inupt + + Parameters + ------------- + aperture : None or Float + transmissivity : None or Float + permeability : None or Float + + Returns + --------- + The hydraulic property type. Exactly one of the three parameters must be a float or an exception will be thrown + Notes + -------""" + + #Determine Hydraulic Property type + + hy_prop_type = None + + if aperture is not None: + hy_prop_type = 'aperture' + + if transmissivity is not None: + if hy_prop_type != None: + error = "\nPlease specify exactly one of the following for user defined fracture: aperture, transmissivity, permeability\n" + sys.stderr.write(error) + sys.exit(1) + else: + hy_prop_type = 'transmissivity' + + if permeability is not None: + if hy_prop_type != None: + error = "\nPlease specify exactly one of the following for user defined fracture: aperture, transmissivity, permeability\n" + sys.stderr.write(error) + sys.exit(1) + else: + hy_prop_type = 'permeability' + + if hy_prop_type == None: + error = "\nPlease specify exactly one of the following for user defined fracture: aperture, transmissivity, permeability\n" + sys.stderr.write(error) + sys.exit(1) + + return hy_prop_type +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/generation/output_report/gen_output.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/generation/output_report/gen_output.html new file mode 100644 index 000000000..970168f55 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/generation/output_report/gen_output.html @@ -0,0 +1,245 @@ + + + + + + pydfnworks.dfnGen.generation.output_report.gen_output — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for pydfnworks.dfnGen.generation.output_report.gen_output

+"""
+  :filename: gen_output.py
+  :synopsis: Main driver for dfnGen output report
+  :version: 1.0
+  :maintainer: Jeffrey Hyman 
+  :moduleauthor: Jeffrey Hyman <jhyman@lanl.gov>
+"""
+
+import os
+import matplotlib
+
+matplotlib.use("Agg")
+import matplotlib.pylab as plt
+from matplotlib import rc
+
+rc('text', usetex=True)
+
+import pydfnworks.dfnGen.generation.generator
+from pydfnworks.dfnGen.generation.output_report.gather_information import *
+from pydfnworks.dfnGen.generation.output_report.plot_fracture_orientations import plot_fracture_orientations
+from pydfnworks.dfnGen.generation.output_report.plot_fracture_radii import plot_fracture_radii
+from pydfnworks.dfnGen.generation.output_report.plot_fracture_centers import plot_fracture_centers
+from pydfnworks.dfnGen.generation.output_report.plot_fram_information import plot_fram_information
+from pydfnworks.dfnGen.generation.output_report.plot_intersection_lengths import plot_intersection_lengths
+from pydfnworks.dfnGen.generation.output_report.make_pdf import make_pdf
+
+
+def setup_output_directory(params):
+    """ Create working dictionary for plots. There is one directory for the entire network information and one for each family.
+
+  Parameters
+  ------------
+    params : dictionary
+      Output report dictionary containing general parameters. See output_report for more details
+
+  Returns
+  ---------
+    None
+
+  Notes
+  --------
+    None
+
+
+  """
+
+    if not os.path.isdir(params["output_dir"]):
+        os.mkdir(params["output_dir"])
+    if not os.path.isdir(f"{params['output_dir']}/network"):
+        os.mkdir(f"{params['output_dir']}/network")
+    for i in range(1, params["num_families"] + 1):
+        if not os.path.isdir(f"{params['output_dir']}/family_{i}"):
+            os.mkdir(f"{params['output_dir']}/family_{i}")
+
+
+
+[docs] +def output_report(self, verbose=True, output_dir="dfnGen_output_report"): + """ Creates a PDF output report for the network created by DFNGen. Plots of the fracture lengths, locations, orientations are produced for each family. Files are written into "output_dir/family_{id}/". Information about the whole network are also created and written into "output_dir/network/" + + Parameters + ---------- + self : object + DFN Class object + verbose : bool + Toggle for the amount of information printed to screen. If true, progress information printed to screen + output_dir : string + Name of directory where all plots are saved + + Returns + -------- + None + + Notes + --------- + Final output report is named "jobname"_output_report.pdf + User defined fractures (ellipses, rectangles, and polygons) are not supported at this time. + + + """ + cwd = os.getcwd() + print("=" * 80) + print('Creating Report of DFN generation') + print("=" * 80 + "\n") + print('--> Gathering Network Information') + # Create a list of dictionaries with information about fracture family + families = get_family_information() + # Create a list of dictionaries with information about fracture + fractures = get_fracture_information() + # Combine information of the families and fractures, e.g., which fracture are in each family, and create a dictionary with parameters used throughout the output report + families, fractures, params = combine_family_and_fracture_information( + families, fractures, self.num_frac, self.domain) + params, families = parse_dfn_output(params, families) + + params["verbose"] = verbose + params["jobname"] = self.local_jobname + params["output_dir"] = output_dir + + setup_output_directory(params) + + # Create Plots + if len(families) > 0: + print('--> Plotting Information') + plot_fracture_centers(params, families, fractures) + plot_fracture_radii(params, families, fractures) + plot_fracture_orientations(params, families, fractures) + plot_fram_information(params) + # # Combine plots into a pdf + make_pdf(params, families, fractures) + print( + f"--> Output report is written into {self.local_jobname}_output_report.pdf\n" + ) + + else: + print( + "--> There are no stochastic families. An output PDF will not be generated.\n" + ) + + # Return to main directory + print("=" * 80) + print("Creating Report of DFN generation complete") + print("=" * 80 + "\n") + os.chdir(self.jobname)
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/generation/stress.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/generation/stress.html new file mode 100644 index 000000000..e6d3630e0 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/generation/stress.html @@ -0,0 +1,276 @@ + + + + + + pydfnworks.dfnGen.generation.stress — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for pydfnworks.dfnGen.generation.stress

+import math as m
+import numpy as np
+
+# from pydfnworks
+from pydfnworks.dfnGen.generation.hydraulic_properties import convert
+
+
+
+[docs] +def stress_based_apertures(self, + sigma_mat, + friction_angle=25.0, + dilation_angle=5, + critical_shear_displacement=0.003, + shear_modulus=10.e9, + min_b=1e-10, + shear_stiffness=400.e9): + """ Takes stress tensor as input (defined in dfn run file) and calculates new apertures based on Bandis equations. New aperture and permeability values are written to files. + + + Parameters + ---------------------- + sigma_mat : array + 3 x 3 stress tensor (units in Pa) + friction_angle : float + Friction angle (Degrees) + dilation_angle : float + Dilation angle (Degrees) + critical_shear_displacement : float + Critical shear displacement + shear_modulus : float + Shear modulus (Pa) + min_b : float + Minimum aperture (m) + shear_stiffness : float + Shear stiffness (Pa/m) + + Returns + ---------------------- + None + + Notes + ---------------------- + + For details of implementation see + + "Sweeney, Matthew Ryan, and J. D. Hyman. "Stress effects on flow and transport in three‐dimensional fracture networks." Journal of Geophysical Research: Solid Earth 125.8 (2020): e2020JB019754." + + and + + Baghbanan, Alireza, and Lanru Jing. "Stress effects on permeability in a fractured rock mass with correlated fracture length and aperture." International journal of rock mechanics and mining sciences 45.8 (2008): 1320-1334. + + and + + Zhao, Zhihong, et al. "Impact of stress on solute transport in a fracture network: A comparison study." Journal of Rock Mechanics and Geotechnical Engineering 5.2 (2013): 110-123. + + """ + print("--> Computing aperture based on stress tensor") + print("\n--> Stress Tensor (Pa):\n") + print( + f"\t{sigma_mat[0][0]:0.2e} {sigma_mat[0][1]:0.2e} {sigma_mat[0][2]:0.2e}" + ) + print( + f"\t{sigma_mat[1][0]:0.2e} {sigma_mat[1][1]:0.2e} {sigma_mat[1][2]:0.2e}" + ) + print( + f"\t{sigma_mat[2][0]:0.2e} {sigma_mat[2][1]:0.2e} {sigma_mat[2][2]:0.2e}" + ) + print() + + # write stress to file. + with open("stress.dat", "w") as fstress: + fstress.write( + f"\t{sigma_mat[0][0]:0.2e} {sigma_mat[0][1]:0.2e} {sigma_mat[0][2]:0.2e}" + ) + fstress.write( + f"\t{sigma_mat[1][0]:0.2e} {sigma_mat[1][1]:0.2e} {sigma_mat[1][2]:0.2e}" + ) + fstress.write( + f"\t{sigma_mat[2][0]:0.2e} {sigma_mat[2][1]:0.2e} {sigma_mat[2][2]:0.2e}" + ) + + # read fracture data: + initial_aperture = self.aperture + normals = self.normal_vectors + radii_frac = self.radii[:, + 0] #og in case of bugs np.genfromtxt('radii_Final.dat', skip_header=2)[:, 0] + num_frac = len(initial_aperture) + b = np.zeros(num_frac) + + # Cycle through fractures and compute new aperture base on stress field and user defined parameters + for i in range(num_frac): + # Magnitude of normal stress + sigma_mag = sigma_mat[0][0]*(normals[i][0])**2 + \ + sigma_mat[1][1]*(normals[i][1])**2 + \ + sigma_mat[2][2]*(normals[i][2])**2 + \ + 2*(sigma_mat[0][1]*normals[i][0]*normals[i][1] + \ + sigma_mat[1][2]*normals[i][1]*normals[i][2] + \ + sigma_mat[0][2]*normals[i][0]*normals[i][2]) + + T_1 = sigma_mat[0][0]*normals[i][0] + \ + sigma_mat[0][1]*normals[i][1] + \ + sigma_mat[0][2]*normals[i][2] + + T_2 = sigma_mat[1][0]*normals[i][0] + \ + sigma_mat[1][1]*normals[i][1] + \ + sigma_mat[1][2]*normals[i][2] + + T_3 = sigma_mat[2][0]*normals[i][0] + \ + sigma_mat[2][1]*normals[i][1] + \ + sigma_mat[2][2]*normals[i][2] + + stress_sqr = (T_1)**2 + (T_2)**2 + (T_3)**2 + # Magnitude of shear stress + shear_stress = np.sqrt(max(0, stress_sqr - (sigma_mag)**2)) + # Critical normal stress (see Zhao et al. 2013 JRMGE) + sigma_nc = (0.487 * initial_aperture[i] * 1e6 + 2.51) * 1e6 + # Normal displacement + normal_displacement = (9 * sigma_mag * initial_aperture[i]) / ( + sigma_nc + 10 * sigma_mag) + # Shear dilation + # print(normal_displacement) + shear_stress_critical = sigma_mag * m.tan(m.radians(friction_angle)) + # Fracture half length + l = radii_frac[i] + + # rock stiffness + rock_stiffness = 0.92 * shear_modulus / l + ks1 = shear_stiffness + rock_stiffness + ks2 = rock_stiffness + # + if shear_stress > shear_stress_critical: + dilation_tmp = (shear_stress - shear_stress_critical * + (1 - ks2 / ks1)) / (ks2) + else: + dilation_tmp = 0 + + dilation = min(dilation_tmp, critical_shear_displacement) * m.tan( + m.radians(dilation_angle)) + #dilation = dilation_tmp * m.tan(m.radians(dilation_angle)) + # take the max of the computed and provided minimum aperture. + b[i] = max(min_b, initial_aperture[i] - normal_displacement + dilation) + + diff = abs(b - initial_aperture) + diff2 = diff**2 + print(f"--> L2 change in apertures {np.sqrt(diff.sum()):0.2e}") + print(f"--> Maximum change in apertures {max(diff):0.2e}") + + self.perm = convert(b, 'aperture', 'permeability') + self.transmissivity = convert(b, 'aperture', 'transmissivity') + self.aperture = b + # self.dump_hydraulic_values() + + print("--> Computing aperture based on stress field complete ")
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/add_attribute_to_mesh.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/add_attribute_to_mesh.html new file mode 100644 index 000000000..ff22edd55 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/add_attribute_to_mesh.html @@ -0,0 +1,272 @@ + + + + + + pydfnworks.dfnGen.meshing.add_attribute_to_mesh — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for pydfnworks.dfnGen.meshing.add_attribute_to_mesh

+import subprocess
+from numpy import genfromtxt, zeros, savetxt
+import sys
+import os
+
+from pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn_helper import run_lagrit_script
+from pydfnworks.general import helper_functions as hf
+
+
+def create_variable_file(variable, variable_file, matid_file="materialid.dat"):
+    """
+    Creates a node based file for variables
+
+    Parameters
+    -----------
+        variable : string
+            name of variable
+        variable_file : string
+            name of file containing variable files. Must be a single column where each line corresponds to that fracture number. 
+        matid_file : string
+            name of materialid file produced by large. Normally produced by run_meshing.
+
+    Returns
+    ----------
+        variable_file_by_node : string
+            name of file containing node based values of the variable
+
+    """
+
+    print(f"--> Making {variable} by node file")
+    values = genfromtxt(variable_file, skip_header=0, usecols=(-1))
+    if not os.path.isfile(matid_file):
+        hf.print_error(f"Cannot locate the file '{matid_file}")
+
+    nodes = genfromtxt(matid_file, skip_header=3).astype(int)
+    value_by_node = zeros(len(nodes))
+    for i, n in enumerate(nodes):
+        value_by_node[i] = values[n - 1]
+    variable_file_by_node = f"{variable}_by_node.dat"
+    savetxt(variable_file_by_node, value_by_node)
+    print("--> Complete")
+    return variable_file_by_node
+
+
+def create_lagrit_append_script(variable, variable_file, mesh_file_in,
+                                mesh_file_out):
+    """
+    Creates a LaGriT script to append the attribute to the mesh 
+
+    Parameters
+    -----------
+        variable : string
+            name of variable
+        variable_file : string
+            name of file containing variable files. Must be a single column where each line corresponds to that node number in the mesh
+        mesh_file_in : string
+            Name of source mesh file
+        mesh_file_out : string
+            Name of Target mesh file
+    Returns
+    ----------
+        lagrit_file : string
+            Name of LaGriT output file
+    """
+    print("--> Making LaGriT script")
+    lagrit_script = f'''
+read / {mesh_file_in} / mo1
+cmo / addatt / mo1 / {variable} / vdouble / scalar / nnodes
+cmo / setatt / mo1 / {variable} / 1 0 0 / 1
+cmo / readatt / mo1 / {variable} / 1, 0, 0 / {variable_file} 
+dump / {mesh_file_out} / mo1 
+finish
+'''
+
+    lagrit_file = f"add_{variable}_to_mesh.lgi"
+    with open(lagrit_file, "w") as fp:
+        fp.write(lagrit_script)
+        fp.flush()
+    print("--> Complete")
+    return lagrit_file
+
+
+
+[docs] +def add_variable_to_mesh(self, + variable, + variable_file, + mesh_file_in, + mesh_file_out=None, + node_based=False): + """ + Adds a variable to the nodes of a mesh. Can be either fracture (material) based + or node based. + + Parameters + ----------- + self : object + DFN Class + variable : string + name of variable + variable_file : string + name of file containing variable files. Must be a single column where each line corresponds to that node number in the mesh + mesh_file_in : string + Name of source mesh file + mesh_file_out : string + Name of Target mesh file. If no name if provide, mesh_file_in will be used + node_based : bool + Set to True if variable_file contains node-based values, Set to False + if variable_file provide fracture based values + + Returns + ---------- + lagrit_file : string + Name of LaGriT output file + """ + + # Check input files + if not os.path.isfile(variable_file): + hf.print_error( + f"Error -- in function 'add_variable_to_mesh'. The file {variable_file} is not in current directory. Please check the filename." + ) + + if not os.path.isfile(mesh_file_in): + hf.print_error( + f"Error -- in function 'add_variable_to_mesh'. The mesh file {mesh_file_in} is not in current directory. Please check the filename." + ) + + # if an output mesh file is not provided, set target mesh to be the source mesh. + if mesh_file_out is None: + mesh_file_out = mesh_file_in + + print( + f"--> Adding attribute in {variable_file} to mesh file {mesh_file_in}.\n--> Output writting into {mesh_file_out}" + ) + + if node_based: + print(f"--> Expecting node-based values") + lagrit_file = create_lagrit_append_script(variable, variable_file, + mesh_file_in, mesh_file_out) + else: + variable_file_by_node = create_variable_file(variable, variable_file) + lagrit_file = create_lagrit_append_script(variable, + variable_file_by_node, + mesh_file_in, mesh_file_out) + + run_lagrit_script(lagrit_file) + + print( + f"--> Complete: Adding attribute in {variable_file} to mesh file {mesh_file_in}.\n--> Output writting into {mesh_file_out}" + )
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/dfm/mesh_dfm.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/dfm/mesh_dfm.html new file mode 100644 index 000000000..8a1b2be42 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/dfm/mesh_dfm.html @@ -0,0 +1,1214 @@ + + + + + + pydfnworks.dfnGen.meshing.dfm.mesh_dfm — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for pydfnworks.dfnGen.meshing.dfm.mesh_dfm

+"""
+.. module:: mesh_dfm.py
+   :synopsis: meshing driver for conforming DFM  
+.. moduleauthor:: Jeffrey Hyman <jhyman@lanl.gov>
+
+"""
+
+import os
+import sys
+import shutil
+import glob 
+
+# pydfnworks Modules
+from pydfnworks.dfnGen.meshing.mesh_dfn import mesh_dfn_helper as mh
+
+def setup_mesh_dfm_directory(jobname, dirname):
+    """ Setup working directory for meshing the DFM. 
+
+    Parameters
+    ----------------
+        jobname : string
+            path to DFN working directory 
+        dirname : string 
+            name of working directory
+
+    Returns
+    --------------
+        None
+
+    Notes
+    -------------
+        None 
+    """
+    path = jobname + os.sep + dirname
+    try: 
+        os.mkdir(path)
+        os.chdir(path)
+    except:
+        shutil.rmtree(path)
+        os.mkdir(path)
+        os.chdir(path)
+
+
+    print(f"--> Working directory is now {os.getcwd()}")
+    # Make symbolic links to required files
+    try:
+        os.symlink(jobname + os.sep + "full_mesh.inp", "full_mesh.inp")
+    except:
+        error = f"Error. Unable to make symbolic link to full_mesh.inp file for DFM meshing from {jobname}.\nExitting program."
+        sys.stderr.write(error)
+        sys.exit(1)
+
+    print("--> Setting up DFM meshing directory complete")
+
+
+
+def translate_mesh(x1, x2):
+    """
+    Moves reduced_mesh.inp from center at x1 to x2 
+
+    Parameters
+    ---------------
+        x1 : list
+            floats x-0, y-1, z-2 - current center
+
+        x2 : list
+            floats x-0, y-1, z-2 - requisted center 
+    Returns
+    --------------
+        None 
+
+    """
+
+    lagrit_script = f"""
+read / avs / full_mesh.inp / MODFN
+trans / 1 0 0 / {x1[0]} {x1[1]} {x1[2]} / {x2[0]} {x2[1]} {x2[2]}
+cmo / printatt / MODFN / -xyz- / minmax
+dump / full_mesh.inp / MODFN
+finish
+"""
+    with open('translate_mesh.lgi', 'w') as fp:
+        fp.write(lagrit_script)
+        fp.flush()
+    mh.run_lagrit_script("translate_mesh.lgi")
+
+
+def create_domain(domain, h):
+    """ Gather domain information. 
+
+    Parameters
+    ----------
+        domain : dict
+            Domain size dictionary from DFN object 
+        h : float 
+            Meshing length scale from DFN object 
+
+    Returns
+    -------
+        num_points : int 
+            Number of points on side of the domain 
+        box_domain : dict
+            dictionary of domain min/max for x,y,z
+
+    Notes
+    ------
+        Exits program is too many points are in domain. 
+        Assuming that 
+
+    """
+    box_domain = {"x0": None, "x0": None,
+                  "y0": None, "y1": None, 
+                  "z0": None, "z1": None 
+                  }
+
+    # Extent of domain
+    box_domain['x0'] = -0.5*domain['x']
+    box_domain['x1'] = 0.5*domain['x']
+
+    box_domain['y0'] = -0.5*domain['y'] 
+    box_domain['y1'] = 0.5*domain['y'] 
+
+    box_domain['z0'] = -0.5*domain['z']
+    box_domain['z1'] = 0.5*domain['z']
+
+    # Mesh size in matrix
+    l = h/2
+    # # Number of points in each direction in matrix
+    # num_points = domain['x'] / l + 1
+    # if num_points**3 > 1e8:
+    #     error = f"Error: Too many elements for DFM meshing.\nValue {num_points**3}\nMaximum is 1e8\nExiting Program"
+    #     sys.stderr.write(error)
+    #     sys.exit(1)
+
+    num_points_x = domain['x'] / l + 1
+    num_points_y = domain['y'] / l + 1
+    num_points_z = domain['z'] / l + 1
+    if num_points_x*num_points_y*num_points_z > 1e8:
+        error = f"Error: Too many elements for DFM meshing.\nValue {num_points_x*num_points_y*num_points_z }\nMaximum is 1e8\nExiting Program"
+        sys.stderr.write(error)
+        sys.exit(1)
+    return box_domain, num_points_x, num_points_y, num_points_z 
+
+def dfm_driver(num_points_x, num_points_y, num_points_z , num_fracs, h, box_domain, psets):
+    """ This function creates the main lagrit driver script, which calls the other lagrit scripts.
+
+    Parameters
+    ----------
+        num_points : int 
+            Number of points on side of the domain 
+        num_fracs : int 
+            Number of Fractures in the DFN
+        h : float
+            meshing length scale 
+
+    Returns
+    -------
+        None
+
+    Notes
+    -----
+        None 
+    """
+    floop = ""
+    for ifrac in range(1, num_fracs + 1):
+        if ifrac < num_fracs:
+            floop += f"facets_f{ifrac}.table &\n"
+        else:
+            floop += f"facets_f{ifrac}.table &\n"
+            floop += "left.table &\n"
+            floop += "right.table &\n"
+            floop += "front.table &\n"
+            floop += "back.table &\n"
+            floop += "top.table &\n"
+            floop += "bottom.table"
+            
+    lagrit_script  = f"""#
+#   dfm_mesh_fracture_driver.lgi
+#   dfm_box_dimensions.mlgi
+#   dfm_build_background_mesh.mlgi
+#   dfm_extract_fracture_facets.mlgi
+#   dfm_extract_facets.mlgi
+#
+# extract_fracture_facets.mlgi must be customized for the number of fractures in the DFN
+#
+# This is the dfnWorks DFN mesh
+#
+define / INPUT / full_mesh.inp
+read / avs / INPUT / mo_dfn
+cmo / DELATT / mo_dfn / dfield
+cmo / DELATT / mo_dfn / b_a
+cmo / DELATT / mo_dfn / numbnd
+cmo / DELATT / mo_dfn / if_numb
+#
+# Diagnostics on fracture mesh extents and resolution
+#
+cmo / printatt / mo_dfn / -xyz- / minmax
+quality
+quality/edge_min
+quality/edge_max
+#
+# Define a resolution for the background mesh. This assumes the DFN
+# triangulation is uniform resolution triangles. No attempt is made
+# to adapt the volume mesh resolution to the DFN triangle resolution.
+#
+define / NPX / {num_points_x}
+# define / NPXM1 / {num_points_x - 1}
+define / NPY / {num_points_y}
+# define / NPYM1 / {num_points_y - 1}
+define / NPZ / {num_points_z}
+# define / NPZM1 / {num_points_z - 1}
+define / VERTEX_CLOSE / {h / 4}
+#
+define / MO_BACKGROUND / mo_background
+infile dfm_box_dimensions.mlgi
+infile dfm_build_background_mesh.mlgi
+#
+# Remove all vertices of the tet mesh that fall withing a circumsphere of a fracture triangle.
+#
+addmesh / excavate / mo_tmp / MO_BACKGROUND / mo_dfn
+cmo / delete / MO_BACKGROUND
+#
+# Merge the vertices of the excavated tet mesh with the DFN vertices
+#
+cmo / create / mo_dfm / / / tet
+copypts / mo_dfm / mo_tmp
+cmo / delete / mo_tmp
+compute / distance_field / mo_dfm / mo_dfn / df_vertex
+cmo / select / mo_dfm
+pset / pdel / attribute / df_vertex / 1 0 0 / le VERTEX_CLOSE
+rmpoint / pset get pdel / inclusive
+rmpoint / compress
+cmo / DELATT / mo_dfm / df_vertex
+copypts / mo_dfm / mo_dfn
+#
+cmo / setatt / mo_dfm / imt / 1 0 0 / 1
+cmo / setatt / mo_dfm / itp / 1 0 0 / 0
+cmo / select / mo_dfm
+connect
+cmo / setatt / mo_dfm / itetclr / 1 0 0 / 1
+resetpts / itp
+quality
+#
+#compute / signed_distance_field / mo_dfm / mo_dfn / df_sign_dfm_dfn
+#
+# crush_thin_tets / mo_dfm / 0.25 / 1 0 0 
+dump / avs    / dfm_tet_mesh.inp / mo_dfm
+dump / lagrit / dfm_tet_mesh.lg  / mo_dfm
+dump / exo    / dfm_tet_mesh.exo / mo_dfm
+
+cmo / delete / mo_dfm
+cmo / delete / mo_dfn
+#
+cmo / status / brief
+#
+infile dfm_extract_fracture_facets.mlgi
+infile dfm_diagnostics.mlgi
+#
+# Delete this !!!! 
+# Hardcoded facesets on boundaries for Alex EES17
+cmo / select / mo_dfm
+extract / surfmesh / 1 0 0 / mo_surf / mo_dfm / external
+cmo / addatt / mo_surf / id_side / vint / scalar / nelements
+cmo / select / mo_surf
+settets / normal
+cmo / copyatt / mo_surf mo_surf / id_side itetclr
+cmo / printatt / mo_surf / id_side / minmax
+cmo / DELATT / mo_surf / itetclr0
+cmo / DELATT / mo_surf / idnode0
+cmo / DELATT / mo_surf / idelem0
+cmo / DELATT / mo_surf / facecol
+cmo / DELATT / mo_surf / itetclr1
+cmo / DELATT / mo_surf / idface0
+#
+cmo / copy / mo_tmp / mo_surf
+cmo / select / mo_tmp
+eltset / e_bottom / id_side / eq / 1
+eltset / e_delete / not / e_bottom
+rmpoint / element / eltset get e_delete
+rmpoint / compress
+cmo / DELATT / mo_tmp / id_side
+dump / avs2 / bottom.table / mo_tmp / 0 0 0 2
+cmo / delete / mo_tmp
+#
+cmo / copy / mo_tmp / mo_surf
+cmo / select / mo_tmp
+eltset / e_top / id_side / eq / 2
+eltset / e_delete / not / e_top
+rmpoint / element / eltset get e_delete
+rmpoint / compress
+cmo / DELATT / mo_tmp / id_side
+dump / avs2 / top.table / mo_tmp / 0 0 0 2
+cmo / delete / mo_tmp
+#
+cmo / copy / mo_tmp / mo_surf
+cmo / select / mo_tmp
+eltset / e_right / id_side / eq / 3
+eltset / e_delete / not / e_right
+rmpoint / element / eltset get e_delete
+rmpoint / compress
+cmo / DELATT / mo_tmp / id_side
+dump / avs2 / right.table / mo_tmp / 0 0 0 2
+cmo / delete / mo_tmp
+#
+cmo / copy / mo_tmp / mo_surf
+cmo / select / mo_tmp
+eltset / e_back / id_side / eq / 4
+eltset / e_delete / not / e_back
+rmpoint / element / eltset get e_delete
+rmpoint / compress
+cmo / DELATT / mo_tmp / id_side
+dump / avs2 / back.table / mo_tmp / 0 0 0 2
+cmo / delete / mo_tmp
+#
+cmo / copy / mo_tmp / mo_surf
+cmo / select / mo_tmp
+eltset / e_left / id_side / eq / 5
+eltset / e_delete / not / e_left
+rmpoint / element / eltset get e_delete
+rmpoint / compress
+cmo / DELATT / mo_tmp / id_side
+dump / avs2 / left.table / mo_tmp / 0 0 0 2
+cmo / delete / mo_tmp
+#
+cmo / copy / mo_tmp / mo_surf
+cmo / select / mo_tmp
+eltset / e_front / id_side / eq / 6
+eltset / e_delete / not / e_front
+rmpoint / element / eltset get e_delete
+rmpoint / compress
+cmo / DELATT / mo_tmp / id_side
+dump / avs2 / front.table / mo_tmp / 0 0 0 2
+cmo / delete / mo_tmp
+#
+"""
+    
+    if psets:
+        eps = h/4
+        lagrit_script += f"""
+cmo / select / mo_dfm
+cmo / printatt / mo_dfm / -xyz- / minmax
+
+pset/ pleft / geom / xyz / 1, 0, 0 /  &
+     {box_domain['x0'] - eps} {box_domain['y0']} {box_domain['z0']} / {box_domain['x0'] + eps} {box_domain['y1']} {box_domain['z1']}  / 0,0,0
+pset/ pright / geom / xyz / 1, 0, 0 / &
+    {box_domain['x1'] - eps} {box_domain['y0']} {box_domain['z0']} / {box_domain['x1'] + eps} {box_domain['y1']} {box_domain['z1']}  / 0,0,0
+
+pset / pfront / geom / xyz / 1, 0, 0 / & 
+    {box_domain['x0']} {box_domain['y0'] - eps}  {box_domain['z0']} / {box_domain['x1']}  {box_domain['y0'] + eps}  {box_domain['z1']}  / 0,0,0 
+pset / pback / geom / xyz / 1, 0, 0 / & 
+    {box_domain['x0']} {box_domain['y1'] - eps}  {box_domain['z0']}  / {box_domain['x1']}  {box_domain['y1'] + eps}  {box_domain['z1']}  / 0,0,0 
+
+pset / pbottom / geom / xyz / 1, 0, 0 / &
+    {box_domain['x0']} {box_domain['y0']} {box_domain['z0'] - eps} / {box_domain['x1']}  {box_domain['y1']} {box_domain['z0'] + eps}/ 0,0,0 
+pset / ptop / geom / xyz / 1, 0, 0 /  & 
+    {box_domain['x0']} {box_domain['y0']} {box_domain['z1'] - eps} / {box_domain['x1']}  {box_domain['y1']} {box_domain['z1'] + eps} / 0,0,0 
+
+# corners of the mesh 1
+pset / p_tmp / inter / pleft pbottom
+pset / p_corner_lfb / inter / p_tmp pfront 
+pset / p_tmp / delete 
+
+pset / pbottom / not / pbottom p_corner_lfb
+pset / pleft / not / pleft p_corner_lfb
+pset / pfront / not / pfront p_corner_lfb
+
+
+cmo / addatt / mo_dfm / p_corner_lfb / vint / scalar / nnodes
+cmo/setatt / mo_dfm / p_corner_lfb / 1,0,0 / 0
+cmo/setatt / mo_dfm / p_corner_lfb /pset,get,p_corner_lfb / 1
+
+# corners of the mesh 2
+pset / p_tmp / inter / pright pbottom
+pset / p_corner_rfb / inter / p_tmp pfront 
+pset / p_tmp / delete 
+
+pset / pbottom / not / pbottom p_corner_rfb
+pset / pright / not / pright p_rfp_corner
+pset / pfront / not / pfront p_corner_rfb
+
+cmo / addatt / mo_dfm / p_corner_rfb / vint / scalar / nnodes
+cmo/setatt / mo_dfm / p_corner_rfb / 1,0,0 / 0
+cmo/setatt / mo_dfm / p_corner_rfb /pset,get,p_corner_rfb / 1
+
+# corners of the mesh 3
+pset / p_tmp / inter / pleft ptop
+pset / p_corner_lft / inter / p_tmp pfront 
+
+pset / pbottom / not / pbottom p_corner_lft
+pset / pleft / not / pleft p_corner_lft
+pset / pfront / not / pfront p_corner_lft
+pset / p_tmp / delete 
+
+cmo / addatt / mo_dfm / p_corner_lft / vint / scalar / nnodes
+cmo/setatt / mo_dfm / p_corner_lft / 1,0,0 / 0
+cmo/setatt / mo_dfm / p_corner_lft /pset,get,p_corner_lft / 1
+
+# corners of the mesh 4
+pset / p_tmp / inter / pright ptop 
+pset / p_corner_rft / inter / p_tmp pfront 
+pset / p_tmp / delete 
+
+pset / ptop / not / ptop p_corner_rft
+pset / pright / not / pright p_corner_rft
+pset / pfront / not / pfront p_corner_rft
+
+
+
+cmo / addatt / mo_dfm / p_corner_rft / vint / scalar / nnodes
+cmo/setatt / mo_dfm / p_corner_rft / 1,0,0 / 0
+cmo/setatt / mo_dfm / p_corner_rft /pset,get,p_corner_rft / 1
+
+
+
+### back face 
+
+# corners of the mesh 1
+pset / p_tmp / inter / pleft pbottom
+pset / p_corner_lbb / inter / p_tmp pback 
+pset / p_tmp / delete 
+
+
+# corners of the mesh 2
+pset / p_tmp / inter / pright pbottom
+pset / p_corner_rbb / inter / p_tmp pback 
+pset / p_tmp / delete 
+
+
+# corners of the mesh 3
+pset / p_tmp / inter / pleft ptop
+pset / p_corner_lbt / inter / p_tmp pback 
+pset / p_tmp / delete 
+
+
+# corners of the mesh 4
+pset / p_tmp / inter / pright ptop 
+pset / p_corner_rbt / inter / p_tmp pback 
+pset / p_tmp / delete 
+
+########
+
+cmo / addatt / mo_dfm / p_corner_rbt / vint / scalar / nnodes
+cmo/setatt / mo_dfm / p_corner_rbt / 1,0,0 / 0
+cmo/setatt / mo_dfm / p_corner_rbt /pset,get,p_corner_rbt / 1
+
+cmo / addatt / mo_dfm / p_corner_lbt / vint / scalar / nnodes
+cmo/setatt / mo_dfm / p_corner_lbt / 1,0,0 / 0
+cmo/setatt / mo_dfm / p_corner_lbt /pset,get,p_corner_lbt / 1
+
+
+cmo / addatt / mo_dfm / p_corner_lbb / vint / scalar / nnodes
+cmo/setatt / mo_dfm / p_corner_lbb / 1,0,0 / 0
+cmo/setatt / mo_dfm / p_corner_lbb /pset,get,p_corner_lbb / 1
+
+cmo / addatt / mo_dfm / p_corner_rbb / vint / scalar / nnodes
+cmo/setatt / mo_dfm / p_corner_rbb / 1,0,0 / 0
+cmo/setatt / mo_dfm / p_corner_rbb /pset,get,p_corner_rbb / 1
+
+## clean up PSETS TO MESH 
+pset / pbottom / not / pbottom p_corner_lbb
+pset / pleft / not / pleft p_corner_lbb
+pset / pback / not / pback p_corner_lbb
+
+pset / pbottom / not / pbottom p_corner_rbb
+pset / pright / not / pright p_corner_rbb
+pset / pback / not / pback p_corner_rbb
+
+pset / ptop / not / ptop p_corner_lbt
+pset / pleft / not / pleft p_corner_lbt
+pset / pback / not / pback p_corner_lbt
+
+pset / ptop / not / ptop p_corner_rbt
+pset / pright / not / pright p_corner_rbt
+pset / pback / not / pback p_corner_rbt
+
+
+pset / pbottom / not / pbottom p_corner_lfb
+pset / pleft / not / pleft p_corner_lfb
+pset / pfront / not / pfront p_corner_lfb 
+
+pset / pbottom / not / pbottom p_corner_rfb
+pset / pright / not / pright p_corner_rfb
+pset / pfront / not / pfront p_corner_rfb
+
+pset / ptop / not / ptop p_corner_lft
+pset / pleft / not / pleft p_corner_lft
+pset / pfront / not / pfront p_corner_lft
+
+pset / ptop / not / ptop p_corner_rft
+pset / pright / not / pright p_corner_rft
+pset / pfront / not / pfront p_corner_rft
+
+
+
+### edges ##### 
+
+pset / p_edge_lb / inter / pleft pbottom
+pset / pbottom / not / pbottom p_edge_lb
+pset / pleft / not / pleft p_edge_lb
+
+pset / p_edge_lt / inter / pleft ptop
+pset / ptop / not / ptop p_edge_lt
+pset / pleft / not / pleft p_edge_lt
+
+pset / p_edge_rb / inter / pright pbottom
+pset / pbottom / not / pbottom p_edge_rb
+pset / pright / not / pright p_edge_rb
+
+pset / p_edge_rt / inter / pright ptop 
+pset / ptop / not / ptop p_edge_rt
+pset / pright / not / pright p_edge_rt
+
+####### 
+pset / p_edge_lfr / inter / pleft pfront
+pset / pleft / not / pleft p_edge_lfr
+pset / pfront / not / pfront p_edge_lfr
+
+pset / p_edge_lba / inter / pleft pback 
+pset / pleft / not / pleft p_edge_lba
+pset / pback / not / pback p_edge_lba
+
+pset / p_edge_rfr / inter / pright pfront
+pset / pright / not / pright p_edge_rfr
+pset / pfront / not / pfront p_edge_rfr
+
+pset / p_edge_rba / inter / pright pback 
+pset / pright / not / pright p_edge_rba
+pset / pback / not / pback p_edge_rba
+
+####### 
+
+
+pset / p_edge_frb / inter / pfront pbottom
+pset / pfront / not / pfront p_edge_frb
+pset / pbottom / not / pbottom p_edge_frb
+
+pset / p_edge_bab / inter / pback pbottom
+pset / pback / not / pback p_edge_bab
+pset / pbottom / not / pbottom p_edge_bab
+
+pset / p_edge_frtop / inter / pfront ptop
+pset / pfront / not / pfront p_edge_frtop
+pset / ptop / not / ptop p_edge_frtop
+
+pset / p_edge_btop / inter /  pback ptop
+pset / pback / not / pback p_edge_btop
+pset / ptop / not / ptop p_edge_btop
+
+####### 
+
+cmo / addatt / mo_dfm / right / vint / scalar / nnodes
+cmo/setatt / mo_dfm / right / 1,0,0 / 0
+cmo/setatt / mo_dfm / right /pset,get,pright / 1
+
+cmo / addatt / mo_dfm / back / vint / scalar / nnodes
+cmo/setatt / mo_dfm / back / 1,0,0 / 0
+cmo/setatt / mo_dfm / back /pset,get,pback / 1
+
+
+cmo / addatt / mo_dfm / left / vint / scalar / nnodes
+cmo/setatt / mo_dfm / left / 1,0,0 / 0
+cmo/setatt / mo_dfm / left /pset,get,pleft / 1
+
+cmo / addatt / mo_dfm / top / vint / scalar / nnodes
+cmo/setatt / mo_dfm / top / 1,0,0 / 0
+cmo/setatt / mo_dfm / top /pset,get,ptop / 1
+
+cmo / addatt / mo_dfm / bottom / vint / scalar / nnodes
+cmo/setatt / mo_dfm / bottom / 1,0,0 / 0
+cmo/setatt / mo_dfm / bottom /pset,get,pbottom / 1
+
+cmo / addatt / mo_dfm / front / vint / scalar / nnodes
+cmo/setatt / mo_dfm / front / 1,0,0 / 0
+cmo/setatt / mo_dfm / front /pset,get,pfront / 1
+
+dump / dfm_tet_w_psets.inp / mo_dfm
+dump / exo / dfm_tet_mesh_w_fsets.exo / mo_dfm / psets / / &
+     facesets &
+"""
+        lagrit_script += floop 
+        lagrit_script += """
+finish
+"""
+    else: ## no psets
+        lagrit_script += """
+dump / exo / dfm_tet_mesh_w_fsets.exo / mo_dfm / / / &
+     facesets &
+"""
+        lagrit_script += floop 
+        lagrit_script += """
+finish
+"""
+
+    with open('dfm_mesh_fracture_driver.lgi', 'w') as fp:
+        fp.write(lagrit_script)
+        fp.flush()
+
+    print("Creating dfm_mesh_fracture_driver.lgi file: Complete\n")
+
+def dfm_box(box_domain):    
+    """ This function creates the dfm_box_dimensions.mlgi lagrit script.
+
+    Parameters
+    ----------
+        box_domain : dict
+            dictionary of domain min/max for x,y,z
+  
+    Returns
+    -------
+        None 
+
+    Notes
+    -----
+        None 
+
+    """
+
+    lagrit_script = f"""#
+# Define a bounding box that surrounds, and is a big bigger, than the DFN
+#
+define / X0 / {box_domain['x0']}
+define / X1 / {box_domain['x1']}
+define / Y0 / {box_domain['y0']}
+define / Y1 / {box_domain['y1']}
+define / Z0 / {box_domain['z0']}
+define / Z1 / {box_domain['z1']}
+
+finish
+"""
+    with open('dfm_box_dimensions.mlgi', 'w') as fp:
+        fp.write(lagrit_script)
+        fp.flush()
+
+    print("Creating dfm_box_dimensions.mlgi file: Complete\n")
+
+def dfm_build():
+    """ Create the dfm_build_background_mesh.mlgi lagrit script.
+
+    Parameters
+    ----------
+        None 
+
+    Returns
+    -------
+        None 
+
+    Notes
+    -----
+        Needs to be modified to have different NPX, NPY, NPZ 
+    """
+
+    lagrit_script = """#
+# Build a uniform background point distribution.
+#
+cmo / create / MO_BACKGROUND / / / tet
+createpts / xyz / NPX NPY NPZ / X0 Y0 Z0 / X1 Y1 Z1 / 1 1 1
+cmo / setatt / MO_BACKGROUND / imt / 1 0 0 / 1
+connect / noadd
+cmo / setatt / MO_BACKGROUND / itetclr / 1 0 0 / 1
+#
+finish
+"""
+    with open('dfm_build_background_mesh.mlgi', 'w') as fp: 
+        fp.write(lagrit_script)
+        fp.flush()
+    print("Creating dfm_box_dimensions.mlgi file: Complete\n")
+
+def dfm_fracture_facets(num_frac):
+    """ This function creates the dfm_extract_fracture_facets.mlgi lagrit script.
+
+    Parameters
+    ----------
+        num_frac : int 
+            Number of fractures in the DFN
+    
+    Returns
+    -------
+        None
+
+    Notes
+    -----
+        None 
+    """
+    floop1 = ""
+    floop2 = ""
+    for ifrac in range(1,num_frac+1):
+        floop1 += f"""
+define / FRAC_ID / {ifrac}
+define / FRAC_FILE_OUT / facets_f{ifrac}.inp
+define / FRAC_TABLE_OUT / facets_f{ifrac}.table
+#
+infile dfm_extract_facets.mlgi
+        """
+        if ifrac == 1:
+            floop2 += f"""
+read / avs / facets_f{ifrac}.inp / mo_merge
+cmo / setatt / mo_merge / itetclr / 1 0 0 / {ifrac}
+        """
+        else:
+            floop2 += f"""
+read / avs / facets_f{ifrac}.inp / mo
+cmo / setatt / mo / itetclr / 1 0 0 / {ifrac}
+addmesh / merge / mo_merge / mo_merge / mo
+cmo / delete / mo
+        """
+    lagrit_script = """#
+define / INPUT / full_mesh.inp
+define / MO_ONE_FRAC / mo_tmp_one_fracture
+#
+read / avs / dfm_tet_mesh.inp / mo_dfm
+#
+cmo / create / mo_merge
+cmo / status / brief
+read / avs / INPUT / mo_dfn
+cmo / status / brief
+""" + floop1 + floop2 + """
+dump / avs / facets_merged.inp / mo_merge
+cmo / addatt / mo_merge / id_frac / vint / scalar / nelements
+cmo / copyatt / mo_merge / mo_merge / id_frac / itetclr
+dump / avs / facets_merged.table / mo_merge / 0 0 0 2
+cmo / delete / mo_merge
+
+finish
+"""
+    with open('dfm_extract_fracture_facets.mlgi', 'w') as fp:
+        fp.write(lagrit_script)
+        fp.flush()
+    print("Creating dfm_extract_fracture_facets.mlgi file: Complete\n")
+
+def dfm_facets():
+    """ This function creates the dfm_extract_facets.mlgi lagrit script.
+
+    Parameters
+    ----------
+        None 
+
+    Returns
+    -------
+        None 
+
+    Notes
+    -----
+        None
+
+    """
+
+    lagrit_script = f"""#
+cmo / copy / MO_ONE_FRAC / mo_dfn
+cmo / select / MO_ONE_FRAC
+rmmat / FRAC_ID / element / exclusive
+rmpoint / compress
+resetpts / itp
+cmo / status / brief
+#
+compute / signed_distance_field / mo_dfm / MO_ONE_FRAC / dfield_sign
+
+cmo / delete / MO_ONE_FRAC
+#
+cmo / copy / mo_df_work / mo_dfm
+
+cmo / DELATT / mo_dfm / dfield_sign
+
+cmo / select / mo_df_work
+pset / p1 / attribute / dfield_sign / 1 0 0 / gt 0.0
+pset / p2 / attribute / dfield_sign / 1 0 0 / lt 0.0
+eltset / e1 / inclusive / pset get p1
+eltset / e2 / inclusive / pset get p2
+cmo / setatt / mo_df_work / itetclr / eltset get e1 / 1
+cmo / setatt / mo_df_work / itetclr / eltset get e2 / 2
+resetpts / itp
+extract / surfmesh / 1 0 0 / MO_ONE_FRAC_EXTRACT / mo_df_work
+#
+cmo / select / MO_ONE_FRAC_EXTRACT
+eltset / edel / idelem0 / eq / 0
+rmpoint / element / eltset get edel
+rmpoint / compress
+pset / pdel / attribute / dfield_sign / 1 0 0 / gt / 1.e-9
+rmpoint / pset get pdel / inclusive
+rmpoint / compress
+#
+# idelem0, idelem1 are element numbers
+# idface0, idface1 are the face numbers
+#
+cmo / DELATT / MO_ONE_FRAC_EXTRACT / itetclr0
+cmo / DELATT / MO_ONE_FRAC_EXTRACT / itetclr1
+cmo / DELATT / MO_ONE_FRAC_EXTRACT / facecol
+#
+# Don't keep both sides of the fracture face information.
+#
+cmo / DELATT / MO_ONE_FRAC_EXTRACT / idelem0
+cmo / DELATT / MO_ONE_FRAC_EXTRACT / idface0
+#
+dump / avs2 / FRAC_FILE_OUT  / MO_ONE_FRAC_EXTRACT
+dump / avs2 / FRAC_TABLE_OUT / MO_ONE_FRAC_EXTRACT  / 0 0 0 2
+#
+cmo / delete / MO_ONE_FRAC_EXTRACT
+#
+cmo / status / brief
+#
+finish
+"""
+    with open('dfm_extract_facets.mlgi', 'w') as fp:
+        fp.write(lagrit_script)
+        fp.flush()
+
+    print("Creating dfm_extract_facets.mlgi file: Complete\n")
+
+
+def dfm_diagnostics(h):
+    """
+    
+    """
+    eps_offset = 0.1*h
+    lagrit_script = f"""
+
+# Figure out which cells (tringles) from DFN full_mesh.inp were not reproduced
+# in the DFM tet fracture faces (facets_f1.inp, facets_f2.inp, etc).
+#
+read / avs / full_mesh.inp / mo_full
+#
+read / avs / facets_merged.inp / mo_merge
+#
+# If the above file exists the next lines can be removed.
+#
+# Interpolate does not work well on coincident 2D triangulations. C'est la vie.
+# To work around this turn the facets into prism volumes by giving them a small
+# negative and positive offset and then combine to make prisms. Then you have volume
+# cells to interpolate from.
+#
+#++++++++++++++++++++++++++++++++++++
+# EPS_OFFSET  should be set to ~0.1h
+#
+define / EPS_OFFSET_1  / {-1*eps_offset}
+define / EPS_OFFSET_2  /  {eps_offset}
+#++++++++++++++++++++++++++++++++++++
+offsetsurf / mo_offset_1 / mo_merge / EPS_OFFSET_1
+cmo / setatt / mo_offset_1 / imt / 1 0 0 / 1
+offsetsurf / mo_offset_2 / mo_merge / EPS_OFFSET_2
+cmo / setatt / mo_offset_2 / imt / 1 0 0 / 2
+addmesh / merge / mo_offset_1_2 / mo_offset_1 / mo_offset_2
+pset / p_bottom / attribute / imt / 1 0 0 / eq / 1
+pset / p_top    / attribute / imt / 1 0 0 / eq / 2
+
+extrude / mo_extrude / mo_offset_1_2 / interp / 0 / &
+        pset,get,p_bottom / pset,get,p_top
+
+cmo / delete / mo_merge
+cmo / delete / mo_offset_1
+cmo / delete / mo_offset_2
+cmo / delete / mo_offset_1_2
+cmo / select / mo_extrude
+quality
+
+cmo / addatt / mo_full / mat_interp / vint / scalar / nelements
+cmo / setatt / mo_full / mat_interp / 1 0 0 / 2
+cmo / setatt / mo_extrude / itetclr / 1 0 0 / 1
+interpolate / map / mo_full mat_interp / 1 0 0 / &
+                    mo_extrude itetclr
+dump / avs / tmp_interpolate.inp / mo_full
+cmo / delete / mo_extrude
+cmo / select / mo_full
+eltset / edelete / mat_interp / eq / 1
+
+cmo / addatt / mo_full / volume / e_area
+math / sum / mo_full / area_sum / 1,0,0 / mo_full / e_area
+
+rmpoint / element /  eltset get edelete
+rmpoint / compress
+# Note: If there are no missed cells, this will return:
+# RMPOINT: new point count is            0                                        
+# RMPOINT: new element count is          0                                        
+
+cmo / status / brief
+
+cmo / addatt / mo_full / volume / e_area
+math / sum / mo_full / area_sum / 1,0,0 / mo_full / e_area
+# Note: If there are no missed cells, this MO will be empty and this
+# command will return:
+# 0 element attribute: e_area
+# FATAL ERROR: SUM unable to begin.
+# error in command : math/sum/mo_full/area_sum/1,0,0/mo_full/e_area
+#
+# The attributes that are output in this file could be cleaned up so
+# extra unnecessary information is not included.
+cmo / DELATT / mo_full / e_area
+cmo / DELATT / mo_full / mat_interp
+#
+# NOTE: If there are no missed cells, mo_full will be an empty (#nodes=0) MO
+# No file will be written and LaGriT message will be:
+# WARNING: dumpavs             
+# WARNING: nnodes=0 nelements = 0
+# WARNING: No output
+dump / avs / missed_cells_full_mesh.inp / mo_full
+
+cmo / delete / mo_full
+
+finish
+
+
+
+"""
+    with open('dfm_diagnostics.mlgi', 'w') as fp:
+        fp.write(lagrit_script)
+        fp.flush()
+
+    print("Creating dfm_diagonstics.mlgi file: Complete\n")
+
+
+def create_dfm():
+    """ This function executes the lagrit scripts. 
+    
+    Parameters
+    ----------
+        None    
+
+    Returns
+    -------
+        None
+    
+    Notes
+    -----
+        None
+ 
+    """
+    # Run LaGriT
+    mh.run_lagrit_script(
+        "dfm_mesh_fracture_driver.lgi",
+        quiet=False)
+
+
+
+def cleanup_mesh_dfm_directory():
+    """ Clean up working files from meshing the DFM
+
+    Parameters
+    ---------------
+        None
+
+    Returns
+    ----------------
+        None
+
+    Notes
+    ---------------
+        None
+
+    """
+    print("--> Cleaning up working directory")
+    # clean up LaGrit Scripts
+    lagrit_script_dir = "dfm_lagrit_files" 
+    try:
+        os.mkdir(lagrit_script_dir)
+    except:
+        shutil.rmtree(lagrit_script_dir)
+        os.mkdir(lagrit_script_dir)
+    lagrit_scripts = glob.glob("*lgi")
+    for filename in lagrit_scripts:
+        shutil.copyfile(filename, lagrit_script_dir + os.sep + filename)
+        os.remove(filename)
+
+    extra_files = ['dfm_mesh_fracture_driver.lgi.log','dfm_mesh_fracture_driver.lgi.out',
+                   'tmp_interpolate.inp']
+    for filename in extra_files:
+        shutil.copyfile(filename, lagrit_script_dir + os.sep + filename)
+        os.remove(filename)
+
+    table_dir = "tables"
+    try:
+        os.mkdir(table_dir)
+    except:
+        shutil.rmtree(table_dir)
+        os.mkdir(table_dir)
+
+    table_files = glob.glob("*table")
+    for filename in table_files:
+        shutil.copyfile(filename, table_dir + os.sep + filename)
+        os.remove(filename)
+
+    facets_dir = "facets"
+    try:
+        os.mkdir(facets_dir)
+    except:
+        shutil.rmtree(facets_dir)
+        os.mkdir(facets_dir)
+
+    facet_files = glob.glob("facets*inp")
+    for filename in facet_files:
+        shutil.copyfile(filename, facets_dir + os.sep + filename)
+        os.remove(filename)
+
+
+    print("--> Cleaning up working directory: Complete")
+
+
+def check_dfm_mesh(allowed_percentage):
+    """ Checks how many elements of the DFN meshing are missinf from the DFM. If the percentage missing is larger than the allowed percentage, then the program exists.
+
+    Parameters
+    ----------------
+        allowed_percentage : float
+            Percentage of the mesh allowed to be missing and still continue
+
+    Returns
+    ----------
+        None
+
+    Notes
+    ----------
+        None
+    
+    """
+
+    print("--> Checking for missing elements")
+    if os.path.isfile('missed_cells_full_mesh.inp'):
+        print("--> Missing elements have been found.")
+        print(f"--> Missing elements are in the file 'missed_cells_full_mesh.inp' if you want to see them.")
+        # get number of missed elements in the 
+        with open('missed_cells_full_mesh.inp', 'r') as fp:
+            line = fp.readline().split()
+            missing_num_elems = int(line[1])
+        # get the total number of elements
+
+        with open('full_mesh.inp', 'r') as fp:
+            line = fp.readline().split()
+            total_num_elems = int(line[1])
+        # Compute percentage and compare
+        missing_percent = 100*(missing_num_elems/total_num_elems)
+        print(f"--> Out of {total_num_elems} elements in the DFN there are {missing_num_elems} missing from the DFM.")
+        print(f"--> That's {missing_percent:0.2f} percent of the mesh.")
+
+        if  missing_percent > allowed_percentage:
+            error = f"*** Error. Missing percent of mesh is larger than tolerance {allowed_percentage} ***\n*** Exitting ***\n "
+            sys.stderr.write(error)
+            sys.exit(1)
+        else:
+            print("--> Doesn't seem to bad. Keep Calm and Carry on.")
+
+    # if the file 'missed_cells_full_mesh.inp' does not exists, this means no elements were missed.  
+    else:
+        print("--> No missinng elements found. ")
+
+
+[docs] +def mesh_dfm(self, dirname = "dfm_mesh", allowed_percentage = 1, psets = False, cleanup = True): + """" Creates a conforming mesh of a DFN using a uniform background tetrahedron mesh. The DFN must be meshed using a uniform triangular mesh. (DFN.mesh_network(uniform_mesh = True)) + + Parameters + ------------------ + dirname : string + name of working directory. Default : dfm_mesh + allowed_percentage : float + Percentage of the mesh allowed to be missing and still continue + cleanup : bool + Clean up working directory. If true dep files are moved into subdirectories + + Returns + --------------- + None + + Notes + -------------- + The final mesh is output in exodus format. This requires that LaGriT is built against exodus. + + """ + + print('=' * 80) + print("Creating conforming DFM mesh using LaGriT : Starting") + print('=' * 80) + + setup_mesh_dfm_directory(self.jobname, dirname) + + center = [self.params['domainCenter']['value'][0],self.params['domainCenter']['value'][1], self.params['domainCenter']['value'][2]] + translate_mesh(center,[0,0,0]) + box_domain, num_points_x, num_points_y, num_points_z = create_domain(self.domain, self.h) + dfm_driver(num_points_x, num_points_y, num_points_z , self.num_frac, self.h, box_domain, psets) + dfm_box(box_domain) + dfm_build() + dfm_fracture_facets(self.num_frac) + dfm_facets() + dfm_diagnostics(self.h) + create_dfm() + + check_dfm_mesh(allowed_percentage) + + translate_mesh([0,0,0], center) + + if cleanup: + cleanup_mesh_dfm_directory() + + print('=' * 80) + print("Creating conforming DFM mesh using LaGriT : Complete") + print('=' * 80)
+ + +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/mapdfn_ecpm/mapdfn_ecpm.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/mapdfn_ecpm/mapdfn_ecpm.html new file mode 100644 index 000000000..324b89f09 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/mapdfn_ecpm/mapdfn_ecpm.html @@ -0,0 +1,224 @@ + + + + + + pydfnworks.dfnGen.meshing.mapdfn_ecpm.mapdfn_ecpm — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for pydfnworks.dfnGen.meshing.mapdfn_ecpm.mapdfn_ecpm

+'''
+   mapdfn2pflotran.py
+
+   Call methods in mapdfn.py to take output of dfnWorks-Version2.0, create
+   equivalent continuous porous medium representation, and write parameters
+   (permeability, porosity, tortuosity) to files for use with PFLOTRAN.
+
+   Usage: Edit values for origin, nx, ny, nz, d, k_background, bulk_por,
+          tortuosity factor, and h5origin.
+          Paths and filenames are hardwired and may also need to be checked.
+          As written, they assume script is being called from a subdirectory.
+          Then: python mapdfn2pflotran.py
+
+   Dependencies: mapdfn.py
+                 numpy
+                 h5py
+
+   Author: 
+
+   Date: 07/13/18
+   SAND Number: SAND2018-7605 O
+
+'''
+import time
+
+from pydfnworks.dfnGen.meshing.mapdfn_ecpm.mapdfn_upscale import mapdfn_porosity, mapdfn_perm_iso, mapdfn_perm_aniso
+from pydfnworks.dfnGen.meshing.mapdfn_ecpm.mapdfn_io import write_h5_files
+from pydfnworks.dfnGen.meshing.mapdfn_ecpm.mapdfn_helper_functions import setup_output_dir, setup_domain
+
+
+
+[docs] +def mapdfn_ecpm(self, + matrix_perm, + matrix_porosity, + cell_size, + matrix_on = False, + tortuosity_factor=0.001, + lump_diag_terms=False, + correction_factor=True, + output_dir="mapdfn_ecpm"): + """ This script takes the top-level directory of the dfn and maps it to an ecpm, saving the ecpm files in that directory + + Parameters + ----------------- + self : dfnWorks object + + cell_size : float + The cell size (meters) to use for the meshing + + correction_factor : boolean + Apply stairstep correction from EDFM to not applied to permeability + + + Returns + ----------------- + None + + Authors + ----------------- + Emily Stein (ergiamb@sandia.gov) + Applied Systems Analysis and Research, 8844 + Sandia National Laboratories + + Edited by Teresa Portone (tporton@sandia.gov) 11/2020 to take arguments. + + Rosie Leone + + Jeffrey Hyman 07/2023 - Integration with pydfnWorks + + Notes + ----------------- + + + """ + print("\n") + print('=' * 80) + print("* Starting MAPDFN - ECPM") + print('=' * 80) + + # setup the domain + filenames = setup_output_dir(output_dir, self.jobname) + origin, nx, ny, nz, num_cells = setup_domain(self.domain, cell_size) + + # id cells that intersect the DFN + cell_fracture_id = self.mapdfn_tag_cells(origin, num_cells, nx, ny, nz, + cell_size) + + porosity, k_iso, k_aniso = self.mapdfn_upscale(num_cells, cell_fracture_id, + cell_size, matrix_porosity, + matrix_perm, + lump_diag_terms, + correction_factor) + + # write evereything to files + write_h5_files(filenames, nx, ny, nz, cell_size, cell_fracture_id, k_iso, + k_aniso, porosity, matrix_perm, tortuosity_factor, matrix_on) + + print('=' * 80) + print("* MAPDFN Complete") + print('=' * 80) + print("\n")
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/mesh_dfn/mesh_dfn.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/mesh_dfn/mesh_dfn.html new file mode 100644 index 000000000..8ae7c4f1a --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/mesh_dfn/mesh_dfn.html @@ -0,0 +1,290 @@ + + + + + + pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn

+"""
+.. module:: mesh_dfn.py
+   :synopsis: meshing driver for DFN 
+.. moduleauthor:: Jeffrey Hyman <jhyman@lanl.gov>
+
+"""
+
+import os
+import sys
+import shutil
+import timeit
+
+from numpy import genfromtxt, sort
+# pydfnworks Modules
+from pydfnworks.general import helper_functions as hf
+from pydfnworks.dfnGen.meshing.mesh_dfn import mesh_dfn_helper as mh
+from pydfnworks.dfnGen.meshing.mesh_dfn import poisson_driver as lg
+from pydfnworks.dfnGen.meshing.mesh_dfn import run_meshing as run_mesh
+from pydfnworks.dfnGen.meshing.mesh_dfn import general_lagrit_scripts as lgs
+
+
+
+[docs] +def mesh_network(self, + uniform_mesh=False, + min_dist=0.5, + max_dist=10, + max_resolution_factor=10, + well=False, + cleanup=True, + strict=True, + quiet=True): + """ + Mesh fracture network using LaGriT + + Parameters + ---------- + self : object + DFN Class + uniform_mesh : bool + toggle for uniform or variable mesh. Default : False + min_dist : float + Defines the minimum distance from the intersections with resolution h/2. This value is the factor of h, distance = min_dist * h + max_dist : float + Defines the minimum distance from the intersections with resolution max_resolution * h. This value is the factor of h, distance = max_dist * h + max_resolution_factor : float + Maximum factor of the mesh resolultion (max_resolution *h). Depending on the slope of the linear function and size of the fracture, this may not be realized in the mesh. + cleanup : bool + toggle to clean up directory (remove meshing files after a run). Default : True + strict : bool + Toggle if a few mesh errors are acceptable. default is true + quiet : bool + Toggle to turn on/off verbose information to screen about meshing. Default is true, does not print to screen + + Returns + ------- + None + + Notes + ------ + 1. All fractures in self.prune_file must intersect at least 1 other fracture + + """ + + print('=' * 80) + print("Meshing DFN using LaGriT : Starting") + print('=' * 80) + tic = timeit.default_timer() + + mh.setup_meshing_directory() + + ######## Pruning scripts + if self.prune_file: + print( + f"Loading list of fractures to remain in network from {self.prune_file}" + ) + self.fracture_list = sort(genfromtxt(self.prune_file).astype(int)) + print("--> Retaining Fractures: ") + print(self.fracture_list) + print("\n") + if self.path: + self.create_mesh_links(self.path) + else: + hf.print_error( + "User requested pruning in meshing but did not provide path for main files." + ) + + if not self.visual_mode: + self.edit_intersection_files() + ######## Pruning scripts + else: + self.fracture_list = range(1, self.num_frac + 1) + + if well: + add_well_points_to_line_of_intersection() + + slope, intercept = mh.compute_mesh_slope_and_intercept( + self.h, min_dist, max_dist, max_resolution_factor, uniform_mesh) + digits = len(str(self.num_frac)) + ## Create user resolution function + print("--> Creating scripts for LaGriT meshing") + lg.create_poisson_user_function_script() + ## make driver files for each function + for index, frac_id in enumerate(self.fracture_list): + self.create_lagrit_parameters_file(frac_id, index + 1, digits, slope, + intercept, max_resolution_factor) + ## Make viz script or regular script + if self.visual_mode: + lg.create_lagrit_reduced_mesh_script(frac_id, digits) + else: + lg.create_lagrit_poisson_script(frac_id, digits) + + print("--> Creating scripts for LaGriT meshing: complete") + + # ##### FOR SERIAL DEBUG ###### + # for frac_id in self.fracture_list: + # _, msg = run_mesh.mesh_fracture(frac_id, self.visual_mode, self.num_frac) + # if msg < 0: + # error = f"Fracture {frac_id} failed to mesh properly.\nMsg {msg}.\nExiting Program\n" + # sys.stderr.write(error) + # sys.exit(msg) + # # ##### FOR SERIAL DEBUG ###### + + # ### Parallel runs + # if there are more processors than fractures, + if self.ncpu > self.num_frac: + hf.print_warning( + "More processors than fractures requested.\nResetting ncpu to num_frac" + ) + self.ncpu = self.num_frac + + if self.mesh_fractures_header(quiet): + hf.print_error("One or more fractures failed to mesh properly.") + + # ### Parallel runs + self.merge_network() + + ## checking and clean up + if (not self.visual_mode and not self.prune_file and not self.r_fram): + if not mh.check_dudded_points(self.dudded_points): + mh.cleanup_meshing_files() + if strict: + hf.print_error("Incorrect Number of dudded points removed.") + + if not self.visual_mode: + lgs.define_zones() + + self.gather_mesh_information() + + if self.prune_file: + self.clean_up_files_after_prune() + + if cleanup: + mh.cleanup_meshing_files() + + elapsed = timeit.default_timer() - tic + time_sec = elapsed + time_min = elapsed / 60 + time_hrs = elapsed / 3600 + + print("--> Total Time to Mesh Network:") + print( + f"--> {time_sec:.2e} seconds\t{time_min:.2e} minutes\t{time_hrs:.2e} hours" + ) + print() + print('=' * 80) + print("Meshing DFN using LaGriT : Complete") + print('=' * 80)
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/mesh_dfn/mesh_dfn_helper.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/mesh_dfn/mesh_dfn_helper.html new file mode 100644 index 000000000..acd732b12 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/mesh_dfn/mesh_dfn_helper.html @@ -0,0 +1,582 @@ + + + + + + pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn_helper — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn_helper

+"""
+.. module:: mesh_dfn_helper.py
+   :synopsis: helper functions for meshing DFN using LaGriT  
+.. moduleauthor:: Jeffrey Hyman <jhyman@lanl.gov>
+
+"""
+import os
+import sys
+import glob
+import shutil
+import numpy as np
+import subprocess
+import pyvtk as pv
+from pydfnworks.general import helper_functions as hf
+
+
+def check_dudded_points(dudded, hard=False):
+    """Parses LaGrit log_merge_all.out and checks if number of dudded points is the expected number
+
+    Parameters
+    ---------
+        dudded : int 
+            Expected number of dudded points from params.txt
+        hard : bool
+            If hard is false, up to 1% of nodes in the mesh can be missed. If hard is True, no points can be missed. 
+    Returns
+    ---------
+        True/False : bool
+            True if the number of dudded points is correct and  False if the number of dudded points is incorrect 
+    
+    Notes
+    -----
+        If number of dudded points is incorrect by over 1%, program will exit. 
+    """
+
+    print("--> Checking that number of dudded points is correct\n")
+    with open("lagrit_logs/log_merge_all.out", encoding='latin-1') as fp:
+        for line in fp.readlines():
+            if 'Dudding' in line:
+                print(f'--> From LaGriT: {line}')
+                try:
+                    pts = int(line.split()[1])
+                except:
+                    pts = int(line.split()[-1])
+            if 'RMPOINT:' in line:
+                print(f'--> From LaGriT: {line}')
+                total_points = int(line.split()[-1])
+                break
+
+    diff = abs(dudded - pts)
+    print(f"--> Expected Number of dudded points: {dudded}")
+    print(f"--> Actual Number of dudded points: {pts}")
+    print(f"--> Difference between expected and actual dudded points: {diff}")
+    if diff == 0:
+        print('--> The correct number of points were removed. Onward!\n')
+        return True
+    elif diff > 0:
+        hf.print_warning(
+            'Number of points removed does not match the expected value')
+        ## compare with total number poins
+        diff_ratio = 100 * (float(diff) / float(total_points))
+        if diff_ratio < 0.01 and hard == False:
+            print(f"--> However value is small: {diff}")
+            print("--> Proceeding\n")
+            return True
+        else:
+            hf.print_warning(
+                f"Incorrect Number of points removed\nOver 0.01% of nodes removed. Value is {diff_ratio:.2f}"
+            )
+            return False
+
+
+def gather_mesh_information(self):
+    """ Prints information about the final mesh to file
+    
+    Parameters
+    ----------
+        local_jobname : string
+            Name of current DFN job (not path) 
+    visual_mode : bool
+        Determines is reduced_mesh or full_mesh is dumped
+
+    Returns
+    -------
+        None
+   
+    Notes
+    -----
+        None 
+"""
+
+    if self.visual_mode:
+        with open('reduced_mesh.inp', 'r') as finp:
+            header = finp.readline()
+            header = header.split()
+            self.num_nodes = int(header[0])
+        print(
+            f"--> The reduced mesh in reduced_mesh.inp has {self.num_nodes} nodes and {int(header[1])} triangular elements"
+        )
+    else:
+        with open('full_mesh.inp', 'r') as finp:
+            header = finp.readline()
+            header = header.split()
+            self.num_nodes = int(header[0])
+        print(
+            f"--> The primary mesh in full_mesh.inp has {self.num_nodes} nodes and {int(header[1])} triangular elements"
+        )
+        ## get material -ids
+        self.material_ids = np.genfromtxt('materialid.dat',
+                                          skip_header=3).astype(int)
+        self.aperture_cell = np.zeros(self.num_nodes)
+        self.perm_cell = np.zeros(self.num_nodes)
+
+
+
+
+
+
+
+[docs] +def inp2gmv(self, inp_file=None): + """ Convert inp file to gmv file, for general mesh viewer. Name of output file for base.inp is base.gmv + + Parameters + ---------- + self : object + DFN Class + inp_file : str + Name of inp file if not an attribure of self + + Returns + ---------- + None + + Notes + --------- + """ + + if inp_file: + self.inp_file = inp_file + else: + inp_file = self.inp_file + + if not inp_file: + hf.print_error('inp file must be specified in inp2gmv') + + gmv_file = inp_file[:-4] + '.gmv' + + with open('inp2gmv.lgi', 'w') as fid: + fid.write(f'read / avs / {inp_file} / mo\n') + fid.write(f'dump / gmv / {gmv_file} / mo\n') + fid.write('finish \n\n') + + failure = run_lagrit_script('inp2gmv.lgi') + + if failure: + hf.print_error('Failed to run LaGrit to get gmv from inp file.') + print("--> Finished writing gmv format from avs format")
+ + + +
+[docs] +def inp2vtk_python(self): + """ Using Python VTK library, convert inp file to VTK file. + + Parameters + ---------- + self : object + DFN Class + + Returns + -------- + None + + Notes + -------- + For a mesh base.inp, this dumps a VTK file named base.vtk + """ + + if self.flow_solver != "PFLOTRAN": + hf.print_error("inp2vtk requires PFLOTRAN flow solver be selected") + + print("--> Using Python to convert inp files to VTK files") + if self.inp_file: + inp_file = self.inp_file + + if not inp_file: + hf.print_error("inp filename not provided") + + if self.vtk_file: + vtk_file = self.vtk_file + else: + vtk_file = inp_file[:-4] + self.vtk_file = vtk_file + '.vtk' + + print("--> Reading inp data") + + with open(inp_file, 'r') as f: + line = f.readline() + num_nodes = int(line.strip(' ').split()[0]) + num_elems = int(line.strip(' ').split()[1]) + + coord = np.zeros((num_nodes, 3), 'float') + elem_list_tri = [] + elem_list_tetra = [] + + for i in range(num_nodes): + line = f.readline() + coord[i, 0] = float(line.strip(' ').split()[1]) + coord[i, 1] = float(line.strip(' ').split()[2]) + coord[i, 2] = float(line.strip(' ').split()[3]) + + for i in range(num_elems): + line = f.readline().strip(' ').split() + line.pop(0) + line.pop(0) + elem_type = line.pop(0) + if elem_type == 'tri': + elem_list_tri.append([int(i) - 1 for i in line]) + if elem_type == 'tet': + elem_list_tetra.append([int(i) - 1 for i in line]) + + print('--> Writing inp data to vtk format') + vtk = pv.VtkData( + pv.UnstructuredGrid(coord, + tetra=elem_list_tetra, + triangle=elem_list_tri), + 'Unstructured pflotran grid') + + vtk.tofile(vtk_file)
+ + + +
+[docs] +def run_lagrit_script(lagrit_file, output_file=None, quiet=False): + """ + Runs LaGriT + + Parameters + ----------- + ---------- + lagrit_file : string + Name of LaGriT script to run + output_file : string + Name of file to dump LaGriT output + quiet : bool + If false, information will be printed to screen. + + Returns + ---------- + failure: int + If the run was successful, then 0 is returned. + + """ + if output_file == None: + cmd = f"{os.environ['LAGRIT_EXE']} < {lagrit_file} -log {lagrit_file}.log -out {lagrit_file}.out" + else: + cmd = f"{os.environ['LAGRIT_EXE']} < {lagrit_file} -log {output_file}.log -out {output_file}.out > {output_file}.dump" + if not quiet: + print(f"--> Running: {cmd}") + failure = subprocess.call(cmd, shell=True) + if failure: + hf.print_error(f"LaGriT script {lagrit_file} failed to run properly") + else: + if not quiet: + print(f"--> LaGriT script {lagrit_file} ran successfully") + return failure
+ + + +def setup_meshing_directory(): + + dirs = ["lagrit_scripts", "lagrit_logs"] + for d in dirs: + try: + if os.path.isdir(d): + shutil.rmtree(d) + os.mkdir(d) + except: + hf.print(f"Unable to make directory {d}") + + +def cleanup_meshing_files(): + """ Removes mesh files and directories + + Parameters + ---------- + None + + Returns + ------- + None + + Notes + ----- + Only runs if cleanup is true + """ + print("\n--> Cleaning up directory after meshing") + batch_files_to_remove = [ + 'part*', 'log_merge*', 'merge*', 'mesh_poly_CPU*', 'mesh*inp', + 'mesh*lg' + ] + for files in batch_files_to_remove: + for fl in glob.glob(files): + os.remove(fl) + + dirs_to_remove = ['lagrit_scripts', 'lagrit_logs'] + for d in dirs_to_remove: + try: + if os.path.isdir(d): + shutil.rmtree(d) + except: + hf.print_error(f"Unable to remove directory {d}") + + files_to_remove = ['user_resolution.mlgi'] + for filename in files_to_remove: + try: + if os.path.isfile(filename): + os.remove(filename) + except: + hf.print_error(f"Unable to remove file {filename}") + print("--> Cleaning up directory after meshing complete") + + +def compute_mesh_slope_and_intercept(h, min_dist, max_dist, + max_resolution_factor, uniform_mesh): + """ computes the slope and intercept of the meshing resolution. The mesh resolution is a piecewise constant and linear function of the distance (d) from the intersection. + + + if 0 < d < x0*h, then r(d) = h/2 + if x0*h <= d <= x1*h then r(d) = m * d + b + if d < x1 then r(d) = max_resolution_factor*h + + Note that x0 and x1 are factors of h, not spatial units of Length. + + Parameters + ------------------- + h : float + FRAM h scale. Mesh resolution along intersections is h/2 + min_dist : float + Defines the minimum distance from the intersections with resolution h/2. This value is the factor of h, distance = min_dist * h + max_dist : float + Defines the minimum distance from the intersections with resolution max_resolution * h. This value is the factor of h, distance = max_dist * h + max_resolution_factor : float + Maximum factor of the mesh resolultion (max_resolution *h). Depending on the slope of the linear function and size of the fracture, this may not be realized in the mesh. + uniform_mesh : bool + Boolean for uniform mesh resolution + + Returns + ------------------- + slope : float + slope of the linear function of the mesh resolution + intercept : float + Intercept of the linear function of the mesh resolution + + + Notes + ------------------- + + + """ + print("--> Computing mesh resolution function") + if uniform_mesh: + print("--> Uniform Mesh Resolution Selected") + print("*** Mesh resolution ***") + print(f"\tr(d) = {0.5*h}\n") + slope = 0 + intercept = 0.5 * h + else: + print("--> Variable Mesh Resolution Selected") + print( + f"*** Minimum distance [m] from intersection with constant resolution h/2 : {min_dist*h}" + ) + print( + f"*** Maximum distance [m] from intersection variable resolution : {max_dist*h}" + ) + print( + f"*** Upper bound on resolution [m] : {max_resolution_factor*h:0.2f}\n" + ) + ## do some algebra to figure out the slope and intercept + if min_dist >= max_dist: + hf.print_error( + f"min_dist greater than or equal to max_dist.\nmin_dist : {min_dist}\nmax_dist : {max_dist}" + ) + slope = h * (max_resolution_factor - 0.5) / (max_dist - min_dist) + if slope > 1: + hf.print_warning( + f"Meshing slope too large. {slope} > 1. Resetting to 0.9") + slope = 0.9 + + intercept = h * (0.5 - slope * min_dist) + + print("*** Meshing function : ") + x0 = (0.5 * h - intercept) / (slope * h) + x1 = (max_resolution_factor * h - intercept) / (slope * h) + print(f"\tr(d) = {0.5*h:0.2f}\t\t\tfor 0 < d < {x0:0.2f}") + if intercept > 0: + print( + f"\tr(d) = {slope:0.2f} * d + {intercept:0.2f}\t\tfor {x0:0.2f} <= d <= {x1:0.2f} " + ) + else: + print( + f"\tr(d) = {slope:0.2f} * d {intercept:0.2f}\t\tfor {x0:0.2f} < d < {x1:0.2f} " + ) + print( + f"\tr(d) = {max_resolution_factor*h:0.2f} \t\t\tfor {x1:0.2f} <= d" + ) + print("--> Computing mesh resolution function : complete \n") + return slope, intercept +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/udfm/false_connections.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/udfm/false_connections.html new file mode 100644 index 000000000..194781f30 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/udfm/false_connections.html @@ -0,0 +1,226 @@ + + + + + + pydfnworks.dfnGen.meshing.udfm.false_connections — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for pydfnworks.dfnGen.meshing.udfm.false_connections

+"""
+.. module:: false_connections.py
+   :synopsis: Checks for false connections between fractures in upscaled mesh
+.. moduleauthor:: Jeffrey Hyman <jhyman@lanl.gov>
+
+"""
+
+import pickle
+import os
+
+
+
+[docs] +def check_false_connections(self, path="../"): + """ + + Parameters + ---------- + self : object + DFN Class + fmc_filname : string + name of the pickled dictionary of mesh and fracture intersections + + Returns + ------- + num_false_connections : int + number of false connections + num_cell_false : int + number of Voronoi cells with false connections + false_connections : list + list of tuples of false connections created by upscaling + + Notes + ----- + map2continuum and upscale must be run first to create the fracture/mesh intersection + dictionary. Thus must be run in the main job directory which contains connectivity.dat + + + """ + print("--> Checking for false connections in the upscaled mesh.") + # Create symbolic links to create fracture graph + files = ["connectivity.dat", "left.dat", "right.dat", "fracture_info.dat"] + for f in files: + try: + os.symlink(path + f, f) + except: + print(f"--> Warning!!! Unable to make symbolic link to {path+f}") + pass + + # create fracture graph, with arbitrary source/target + G = self.create_graph("fracture", "left", "right") + # remove source and target + G.remove_node("s") + G.remove_node("t") + + # Make a copy of G and remove all edges + H = G.copy() + for u, v in H.edges(): + H.remove_edge(u, v) + + # load the fracture_mesh_connection dictionary + print("--> Loading mesh intersection information") + fmc = pickle.load(open("connections.p", "rb")) + print("--> Complete") + # Get cell ids for the cells that fractures intersect + cells = [key for key in fmc.keys()] + + # walk through the cells and add edges to graph H + # if two fractures are in the same cell + cell_false = [False] * len(cells) + for i, cell in enumerate(cells): + num_conn = len(fmc[cell]) + # If more than one fracture intersects the mesh cell + # add edges + if num_conn > 1: + # add edges between all fractures in a cell + for j in range(num_conn): + id1 = fmc[cell][j][0] + for k in range(j + 1, num_conn): + id2 = fmc[cell][k][0] + H.add_edge(id1, id2) + cell_false[i] = True + + ## check for false connections + print("--> Checking for false connections") + false_connections = [] + for u, v, in H.edges(): + if not G.has_edge(u, v): + print(f"--> False connection between fractures {u} and {v}") + false_connections.append((u, v)) + + if len(false_connections) > 0: + num_false_connections = len(false_connections) + print( + f"--> There are {num_false_connections} false connections between fractures" + ) + num_false_cells = sum(cell_false) + print(f"--> These occur in {num_false_cells} Voronoi cells") + else: + print(f"--> No false connections found") + num_false_cells = 0 + num_false_connections = 0 + + return (num_false_connections, num_false_cells, false_connections)
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/udfm/map2continuum.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/udfm/map2continuum.html new file mode 100644 index 000000000..433321272 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/udfm/map2continuum.html @@ -0,0 +1,1178 @@ + + + + + + pydfnworks.dfnGen.meshing.udfm.map2continuum — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for pydfnworks.dfnGen.meshing.udfm.map2continuum

+"""
+.. module:: map2continuum.py 
+   :synopsis: Produce octree-refined continuum mesh replacing dfn 
+.. moduleauthor:: Matthew Sweeney <msweeney2796@lanl.gov>
+
+"""
+
+import os
+import sys
+import subprocess
+import shutil
+import numpy as np
+from pydfnworks.dfnGen.meshing.mesh_dfn import mesh_dfn_helper as mh
+import time
+import multiprocessing as mp
+import pickle
+
+
+
+[docs] +def map_to_continuum(self, l, orl, path="./", dir_name="octree"): + """ This function generates an octree-refined continuum mesh using the + reduced_mesh.inp as input. To generate the reduced_mesh.inp, one must + turn visualization mode on in the DFN input card. + + Parameters + ---------- + self : object + DFN Class + l : float + Size (m) of level-0 mesh element in the continuum mesh + orl : int + Number of total refinement levels in the octree + path : string + path to primary DFN directory + dir_name : string + name of directory where the octree mesh is created + + Returns + ------- + None + + Notes + ----- + octree_dfn.inp : Mesh file + Octree-refined continuum mesh + fracX.inp : Mesh files + Octree-refined continuum meshes, which contain intersection areas + + """ + print('=' * 80) + print("Meshing Continuum Using LaGrit : Starting") + print('=' * 80) + + if type(orl) is not int or orl < 1: + error = "ERROR: orl must be positive integer. Exiting" + sys.stderr.write(error) + sys.exit(1) + + # Extent of domain + x0 = 0 - (self.domain['x'] / 2.0) + x1 = 0 + (self.domain['x'] / 2.0) + y0 = 0 - (self.domain['y'] / 2.0) + y1 = 0 + (self.domain['y'] / 2.0) + z0 = 0 - (self.domain['z'] / 2.0) + z1 = 0 + (self.domain['z'] / 2.0) + + # Number of cell elements in each direction at coarse level + nx = self.domain['x'] / l + 1 + ny = self.domain['y'] / l + 1 + nz = self.domain['z'] / l + 1 + + if nx * ny * nz > 1e8: + error = "Error: Number of elements too large (> 1e8). Exiting" + sys.stderr.write(error) + sys.exit(1) + + print("\nCreating *.lgi files for octree mesh\n") + try: + os.mkdir(dir_name) + os.mkdir(dir_name + os.sep + "lagrit_scripts") + os.mkdir(dir_name + os.sep + "lagrit_logs") + except OSError: + shutil.rmtree(dir_name) + os.mkdir(dir_name) + os.mkdir(dir_name + os.sep + "lagrit_scripts") + os.mkdir(dir_name + os.sep + "lagrit_logs") + + + ## gather points on polygons + points = self.gather_points() + if self.num_frac == 1: + self.normal_vectors = np.array([self.normal_vectors]) + + + + center = [self.params['domainCenter']['value'][0],self.params['domainCenter']['value'][1], self.params['domainCenter']['value'][2]] + translate_mesh(center,[0,0,0]) + + lagrit_driver(dir_name, nx, ny, nz, self.num_frac, self.normal_vectors,points, center) + + #lagrit_driver(dir_name, nx, ny, nz, self.num_frac, self.normal_vectors, + # self.centers) + + lagrit_parameters(dir_name, orl, x0, x1, y0, y1, z0, z1, nx, ny, nz, + self.h) + lagrit_build(dir_name) + lagrit_intersect(dir_name) + lagrit_hex_to_tet(dir_name) + lagrit_remove(dir_name) + lagrit_run(self, self.num_frac, path, dir_name) + lagrit_strip(self.num_frac) + driver_parallel(self, self.num_frac) + build_dict(self, self.num_frac, delete_files=True) + dir_cleanup() + ## set object variable name + self.inp_file = "octree_dfn.inp" + translate_mesh([0,0,0], center)
+ + + +def translate_mesh(x1, x2): + """ + Moves reduced_mesh.inp from center at x1 to x2 + + Parameters + --------------- + x1 : list + floats x-0, y-1, z-2 - current center + + x2 : list + floats x-0, y-1, z-2 - requisted center + Returns + -------------- + None + + """ + + lagrit_script = f""" +read / avs / reduced_mesh.inp / MODFN +trans / 1 0 0 / {x1[0]} {x1[1]} {x1[2]} / {x2[0]} {x2[1]} {x2[2]} +dump / reduced_mesh.inp / MODFN +finish +""" + with open('translate_mesh.lgi', 'w') as fp: + fp.write(lagrit_script) + fp.flush() + mh.run_lagrit_script("translate_mesh.lgi") + +def lagrit_driver(dir_name, nx, ny, nz, num_poly, normal_vectors, points, center): + """ This function creates the main lagrit driver script, which calls all + lagrit scripts. + + Parameters + ---------- + dir_name : string + Name of working directory + ni : int + Number of cells in each direction + num_poly : int + Number of fractures + normal_vectors : array + Array containing normal vectors of each fracture + points : array + Array containing a point on each fracture + + Returns + ------- + None + + Notes + ----- + None + + """ + xn, yn, zn, xp, yp, zp = 0, 0, 0, 0, 0, 0 + j = num_poly + floop = "" + for i in range(1, int(num_poly + 1)): + xn = normal_vectors[j - 1][0] + yn = normal_vectors[j - 1][1] + zn = normal_vectors[j - 1][2] + xp = points[j - 1][0] + yp = points[j - 1][1] + zp = points[j - 1][2] + floop = """read / avs / mohex2.inp / mohex2 + cmo / DELATT / mohex2 / if_int + read / avs / MOTET_np1.inp / MOTET_np1 + read / avs / MOTET.inp / MOTET + read / avs / reduced_mesh.inp / MODFN + cmo / create / FRACTURE{0} + cmo / copy / FRACTURE{0} / MODFN + cmo / select / FRACTURE{0} + pset / pdel / attribute imt / 1 0 0 / ne / {0} + rmpoint pset, get, pdel + rmpoint compress + resetpts itp + pset / pdel / delete + eltset / edel / itetclr / ne / {0} + rmpoint element eltset, get, edel + rmpoint compress + resetpts itp + eltset / edel / delete + + intersect_elements / mohex2 / FRACTURE{0} / if_int + eltset / erefine / if_int / ne / 0 + pset / pinter / eltset erefine + + cmo / create / temp{0} + cmo / copy / temp{0} / mohex2 + cmo / select / temp{0} + pset / pdel / if_int / 1 0 0 / eq / 0 + rmpoint, pset, get, pdel + rmpoint compress + resetpts itp + pset / pdel / delete + eltset / edel / if_int / eq / 0 + rmpoint element eltset, get, edel + rmpoint compress + resetpts itp + eltset / edel / delete + cmo / setatt / temp{0} / itetclr / 1 0 0 / {0} + cmo / setatt / temp{0} / imt / 1 0 0 / {0} + + cmo / create / TETCOPY + cmo / copy / TETCOPY / MOTET + cmo / select / TETCOPY + interpolate / map / TETCOPY / itetclr / 1 0 0 / temp{0} / itetclr + compute / distance_field / TETCOPY / temp{0} /dfield + cmo / select / TETCOPY + pset / pfrac / attribute / dfield / 1 0 0 / le / 1.e-8 + cmo / setatt / TETCOPY / imt / 1 0 0 / {1} + cmo / setatt / TETCOPY / imt / pset get pfrac / {0} + + cmo / set_id / MOTET_np1 / element / id_cell + cmo / set_id / MOTET_np1 / node / id_vertex + + extract / plane / ptnorm / & + {2} {3} {4} / & + {5} {6} {7} / & + 1 0 0 / moext / MOTET_np1 + cmo / status / brief + + createpts / median + cmo / DELATT / moext / id_cell + cmo / DELATT / moext / id_parent + dump / avs2 / ex_xyz{0}.table / moext 0 0 0 1 + + cmo / addatt / moext / volume / area_tri + cmo / DELATT / moext / xmed + cmo / DELATT / moext / ymed + cmo / DELATT / moext / zmed + dump / avs2 / ex_area{0}.table / moext 0 0 0 1 + cmo / delete / moext + + cmo / select / TETCOPY + cmo / DELATT / TETCOPY / icr1 + cmo / DELATT / TETCOPY / itp1 + cmo / DELATT / TETCOPY / isn1 + + dump / avs2 / frac{0}.inp / TETCOPY + cmo / delete / temp{0} + cmo / delete / TETCOPY + + cmo / select / mohex2 + cmo / setatt / mohex2 / itetclr / eltset get erefine / {0} + cmo / setatt / mohex2 / imt / pset get pinter / {0} + eltset / erefine / delete + pset / pinter / delete + cmo / DELATT / mohex2 / if_int + cmo / delete / FRACTURE{0} + finish + """.format(j, num_poly + 1, xp, yp, zp, xn, yn, zn) + f_name = f'{dir_name}/driver_frac{j}.lgi' + f = open(f_name, 'w') + f.write(floop) + f.flush() + f.close() + j = j - 1 + + f_name = f'{dir_name}/driver_octree_start.lgi' + f = open(f_name, 'w') + fin = (f"""# +# LaGriT control files to build an octree refined hex mesh with refinement +# based on intersection of hex mesh with a DFN triangulation mesh +# +# driver_octree.lgi +# parameters_octree_dfn.mlgi +# build_octree.mlgi +# intersect_refine.mlgi +# hex_to_tet.mlgi +# remove_cells.mlgi +# +# Define some parameters +# +infile parameters_octree_dfn.mlgi +# +# Read in DFN mesh +# +read / FTYPE / FNAME / MODFN +cmo / printatt / MODFN / -xyz- / minmax +# +# Octree refined orthogonal mesh based on intersection with DFN mesh +# +infile build_octree.mlgi +# +# Identify cells in hex mesh that are intersected by DFN mesh +# +# This is the last pass through intersect_elements in order to figure out +# which cells in the fully refined hex mesh are intersected by the dfn mesh +# +intersect_elements / MOHEX / MODFN / if_int +eltset / einter / if_int / ne / 0 +pset / pinter / eltset einter +# +# Use the itetclr(cell) and imt(vertex) attribute to hold the information +# +cmo / setatt / MOHEX / itetclr / 1 0 0 / 1 +cmo / setatt / MOHEX / itetclr / eltset get einter / 2 +cmo / setatt / MOHEX / imt / 1 0 0 / 1 +cmo / setatt / MOHEX / imt / pset get pinter / 2 +# +# Output final hex mesh +# +#dump / avs2 / tmp_hex_refine.inp / MOHEX +# +# Same as above but for np1 hex mesh +# +intersect_elements / MOHEX_np1 / MODFN / if_int +eltset / einter / if_int / ne / 0 +pset / pinter / eltset einter +# +# See above +# +cmo / setatt / MOHEX_np1 / itetclr / 1 0 0 / 1 +cmo / setatt / MOHEX_np1 / itetclr / eltset get einter / 2 +cmo / setatt / MOHEX_np1 / imt / 1 0 0 / 1 +cmo / setatt / MOHEX_np1 / imt / pset get pinter / 2 +#dump / avs2 / tmp_hex_np1_refine.inp / MOHEX_np1 +# +# Convert the hex mesh to a tet mesh +# +infile hex_to_tet.mlgi +# +# Modify the hex data structure from a full octree data structure +# to one in which only the highest level of refined hex is maintained +# and all parent cells are stripped out of the data structure +# +grid2grid / tree_to_fe / mohex2 / MOHEX +#dump / avs / octree_hex_mesh.inp / MOHEX +# +cmo / delete / MOHEX +cmo / select / mohex2 +# +# Remove all but the most refined hex cells +# +loop / do / NTIMEs / 0 N_OCTREE_REFINE_M1 1 / loop_end & +infile remove_cells.mlgi +# +cmo / select / mohex2 +cmo / DELATT / mohex2 / if_int +intersect_elements / mohex2 / MODFN / if_int +cmo / select / mohex2 +eltset / edelete / if_int / eq / 0 +rmpoint / element / eltset get edelete +eltset / edelete / release +rmpoint / compress +# +dump / avs / mohex2.inp / mohex2 +dump / avs / MOTET_np1.inp / MOTET_np1 +dump / avs / MOTET.inp / MOTET +# +cmo / select / MOTET +# +# +cmo / modatt / MOTET / itp / ioflag / l +cmo / modatt / MOTET / isn / ioflag / l +cmo / modatt / MOTET / icr / ioflag / l +# # + +define / ZONE / 1 +define / FOUT / boundary_top +pset / top / attribute / zic / 1 0 0 / gt / ZMAX +pset / top / zone / FOUT / ascii / ZONE + +define / ZONE / 2 +define / FOUT / boundary_bottom +pset / bottom / attribute / zic / 1 0 0 / lt / ZMIN +pset / bottom / zone / FOUT / ascii / ZONE + +define / ZONE / 3 +define / FOUT / boundary_left_w +pset / left_w / attribute / xic / 1 0 0 / lt / XMIN +pset / left_w / zone / FOUT / ascii / ZONE + +define / ZONE / 4 +define / FOUT / boundary_front_n +pset / front_n / attribute / yic / 1 0 0 / gt / YMAX +pset / front_n / zone / FOUT / ascii / ZONE + +define / ZONE / 5 +define / FOUT / boundary_right_e +pset / right_e / attribute / xic / 1 0 0 / gt / XMAX +pset / right_e / zone / FOUT / ascii / ZONE + +define / ZONE / 6 +define / FOUT / boundary_back_s +pset / back_s / attribute / yic / 1 0 0 / lt / YMIN +pset / back_s / zone / FOUT / ascii / ZONE + + +trans / 1 0 0 / 0. 0. 0. / {center[0]}, {center[1]}, {center[2]} + + +dump / pflotran / full_mesh / MOTET / nofilter_zero +dump / avs2 / octree_dfn.inp / MOTET +dump / coord / octree_dfn / MOTET +dump / stor / octree_dfn / MOTET +dump / zone_imt / octree_dfn / MOTET +dump / zone_outside / octree_dfn / MOTET +finish +""") + f.write(fin) + f.flush() + f.close() + print("Creating driver_octree_start.lgi file: Complete\n") + + +def lagrit_parameters(dir_name, orl, x0, x1, y0, y1, z0, z1, nx, ny, nz, h): + """ This function creates the parameters_octree_dfn.mlgi lagrit script. + + Parameters + ---------- + dir_name : string + Name of working directory + orl : int + Number of total refinement levels in the octree + i0, i1 : float + Extent of domain in x, y, z directions + ni : int + Number of cells in each direction + Returns + ------- + None + + Notes + ----- + None + + """ + f_name = f'{dir_name}/parameters_octree_dfn.mlgi' + f = open(f_name, 'w') + fin = """# +# Define some parameters +# +# Input DFN mesh +# +define / FTYPE / avs +define / FNAME / reduced_mesh.inp +# +define / MOHEX / mohex +define / MOTET / motet +# +# Set AMR refinement. 123 means refine in x,y,z directions +# See LaGriT refine command for more options +# +define / REFINE_AMR / 123 +# + """ + f.write(fin) + eps = h * 10**-3 + f.write('define / N_OCTREE_REFINE / %d \n' % orl) + f.write('define / N_OCTREE_REFINE_M1 / %d \n' % (orl - 1)) + f.write('define / N_OCTREE_np1 / %d \n' % (orl + 1)) + f.write('define / N_OCTREE_np1_M1 / %d \n' % (orl)) + f.write('define / X0 / %0.12f \n' % x0) + f.write('define / X1 / %0.12f \n' % x1) + f.write('define / Y0 / %0.12f \n' % y0) + f.write('define / Y1 / %0.12f \n' % y1) + f.write('define / Z0 / %0.12f \n' % z0) + f.write('define / Z1 / %0.12f \n' % z1) + f.write('define / XMAX / %0.12f \n' % (x1 - eps)) + f.write('define / XMIN / %0.12f \n' % (x0 + eps)) + f.write('define / YMAX / %0.12f \n' % (y1 - eps)) + f.write('define / YMIN / %0.12f \n' % (y0 + eps)) + f.write('define / ZMAX / %0.12f \n' % (z1 - eps)) + f.write('define / ZMIN / %0.12f \n' % (z0 + eps)) + f.write('define / NX / %d \n' % nx) + f.write('define / NY / %d \n' % ny) + f.write('define / NZ / %d \n' % nz) + f.write('finish\n') + f.flush() + f.close() + print("Creating parameters_octree_dfn.mlgi file: Complete\n") + + +def lagrit_build(dir_name): + """ This function creates the build_octree.mlgi lagrit script. + + Parameters + ---------- + dir_name : string + name of working directory + + Returns + ------- + None + + Notes + ----- + None + + """ + f_name = f'{dir_name}/build_octree.mlgi' + f = open(f_name, 'w') + fin = """cmo / create / MOHEX / / / hex +createpts / brick / xyz / NX NY NZ / X0 Y0 Z0 / X1 Y1 Z1 / 1 1 1 +cmo / setatt / MOHEX / imt / 1 0 0 / 1 +cmo / setatt / MOHEX / itetclr / 1 0 0 / 1 +resetpts / itp +# +# Print to screen and logfiles the extents of the hex mesh and dfn mesh +# +cmo / printatt / MOHEX / -xyz- / minmax +cmo / select / MODFN +cmo / printatt / MODFN / -xyz- / minmax +# +# Generate copy of hex mesh for upscaling +# +cmo / copy / MOHEX_np1 / MOHEX +# +# Loop through steps to intersect dfn mesh (MODFN) with hex mesh (MOHEX) +# and refine hex mesh based on cell intersections. Loop through +# N_OCTREE_REFINE times +# +loop / do / NTIMEs / 1 N_OCTREE_REFINE 1 / loop_end & +infile intersect_refine.mlgi +# +# See above - except do it once additional time ("np1") +# +loop / do / NTIMEs / 1 N_OCTREE_np1 1 / loop_end & +infile intersect_refine_np1.mlgi +# +finish + """ + f.write(fin) + f.flush() + f.close() + print("Creating build_octree.mlgi file: Complete\n") + + +def lagrit_intersect(dir_name): + """ This function creates the intersect_refine.mlgi lagrit scripts. + + Parameters + ---------- + dir_name : string + name of working directory + + Returns + ------- + None + + Notes + ----- + None + + """ + f_name = f'{dir_name}/intersect_refine.mlgi' + f = open(f_name, 'w') + fin = """# +# Compute mesh to mesh intersection and refine hex mesh +# +intersect_elements / MOHEX / MODFN / if_int +eltset / erefine / if_int / ne / 0 +pset / prefine / eltset erefine +# +# If one wants anisotropic mesh refinement, then the +# variable REFINE_AMR can be set in parameters_octree_dfn.mlgi +# +refine/constant/imt1/linear/element/pset,get,prefine/ & + -1.,0.,0./exclusive/amr REFINE_AMR +# +# Clean up eltset, pset, and if_int attribute +# +eltset / erefine / delete +pset / prefine / delete +cmo / DELATT / MOHEX / if_int +# +# Print out diagnostics +# +quality +cmo / status / brief +# +finish + """ + f.write(fin) + f.flush() + f.close() + print("Creating intersect_refine.mlgi file: Complete\n") + f_name = f'{dir_name}/intersect_refine_np1.mlgi' + f = open(f_name, 'w') + fin = """# +# For comments see intersect_refine.mlgi +# +intersect_elements / MOHEX_np1 / MODFN / if_int +eltset / erefine / if_int / ne / 0 +pset / prefine / eltset erefine +refine/constant/imt1/linear/element/pset,get,prefine/ & +-1.,0.,0./exclusive/amr REFINE_AMR +# +eltset / erefine / delete +pset / prefine / delete +cmo / DELATT / MOHEX_np1 / if_int +# +quality +cmo / status / brief +# +finish + """ + f.write(fin) + f.flush() + f.close() + print("Creating intersect_refine_np1.mlgi file: Complete\n") + + +def lagrit_hex_to_tet(dir_name): + """ This function creates the hex_to_tet.mlgi lagrit script. + + Parameters + ---------- + dir_name : string + name of working directory + + Returns + ------- + None + + Notes + ----- + None + + """ + f_name = f'{dir_name}/hex_to_tet.mlgi' + f = open(f_name, 'w') + fin = """# +# Convert the octree hex mesh to tet mesh by connecting the +# octree vertex collection to a Delaunay mesh +# +cmo / create / MOTET +copypts / MOTET / MOHEX +cmo / select / MOTET +filter 1 0 0 +rmpoint / compress +cmo / setatt / MOTET / imt / 1 0 0 / 1 +cmo / setatt / MOTET / itp / 1 0 0 / 0 +# +# Sort and reorder the nodes based on coordinates +# +sort / MOTET / index / ascending / ikey / xic yic zic +reorder / MOTET / ikey +cmo / DELATT / MOTET / ikey +# +# Connect +# +connect / noadd +cmo / setatt / MOTET / itetclr / 1 0 0 / 1 +resetpts / itp +# +# Do the same for np1 mesh +# +cmo / create / MOTET_np1 +copypts / MOTET_np1 / MOHEX_np1 +cmo / select / MOTET_np1 +filter 1 0 0 +rmpoint / compress +cmo / setatt / MOTET_np1 / imt / 1 0 0 / 1 +cmo / setatt / MOTET_np1 / itp / 1 0 0 / 0 +# +# See above +# +sort / MOTET_np1 / index / ascending / ikey / xic yic zic +reorder / MOTET_np1 / ikey +cmo / DELATT / MOTET_np1 / ikey +# +connect / noadd +cmo / setatt / MOTET_np1 / itetclr / 1 0 0 / 1 +resetpts / itp +# +finish + """ + f.write(fin) + f.flush() + f.close() + print("Creating hex_to_tet.mlgi file: Complete\n") + + +def lagrit_remove(dir_name): + """ This function creates the remove_cells.mlgi lagrit script. + + Parameters + ---------- + dir_name : string + name of working directory + + Returns + ------- + None + + Notes + ----- + None + + """ + f_name = f'{dir_name}/remove_cells.mlgi' + f = open(f_name, 'w') + fin = """# +# Remove cells from hex mesh based on the level of refinement +# itetlev is the refinement level. Original mesh itetlev=0 +# +eltset / edelete / itetlev / eq / NTIMEs +rmpoint / element / eltset get edelete +eltset / edelete / release +rmpoint / compress +# +finish + """ + f.write(fin) + f.flush() + f.close() + print("Creating remove_cells.mlgi file: Complete\n") + + +def lagrit_run(self, num_poly, path, dir_name): + """ This function executes the lagrit scripts. + + Parameters + ---------- + path : string + path to primary DFN directory + dir_name : string + name of directory where the octree mesh is created + + Returns + ------- + None + + Notes + ----- + None + + """ + # Run LaGriT + os.chdir(dir_name) + + if os.path.isfile(path + "reduced_mesh.inp"): + os.symlink(path + "reduced_mesh.inp", "reduced_mesh.inp") + elif os.path.isfile(path + "../" + "reduced_mesh.inp"): + os.symlink(path + "../" + "reduced_mesh.inp", "reduced_mesh.inp") + else: + error = "ERROR!!! Reduced Mesh not found. Please run mesh_dfn with visual_mode=True.\nExiting" + sys.stderr.write(error) + sys.exit(1) + + mh.run_lagrit_script("driver_octree_start.lgi") + + driver_interpolate_parallel(self, num_poly) + + +def lagrit_strip(num_poly): + """ This function strips and replaces the headers of the files, which is + needed to assign the fracture areas to a mesh object. + + Parameters + ---------- + num_poly : int + Number of fractures + + Returns + ------- + None + + Notes + ----- + None + + """ + node_dict = {} + for i in range(1, num_poly + 1): + with open('ex_xyz{0}.table'.format(i), 'r') as infile: + for k, l in enumerate(infile): + pass + node_dict.setdefault(i, []).append(k - 4) + + +# print(node_dict) + + for i in range(1, num_poly + 1): + with open('ex_xyz{0}.table'.format(i), 'r') as infile: + with open('ex_xyz{0}_2.inp'.format(i), 'w') as outfile: + for j, line in enumerate(infile): + if j == 0: + outfile.write("{0} 0 0 0 0\n".format(node_dict[i][0])) + elif j > 4: + outfile.write(line) + outfile.close() + infile.close() + os.remove(f"ex_xyz{i}.table") + with open('ex_area{0}.table'.format(i), 'r') as infile: + with open('ex_area{0}_2.table'.format(i), 'w') as outfile: + for j, line in enumerate(infile): + if j > 2: + outfile.write(line.split()[1]) + outfile.write("\n") + outfile.close() + infile.close() + os.remove(f"ex_area{i}.table") + + +def driver_interpolate_parallel(self, num_poly): + """ This function drives the parallelization of the area sums upscaling. + + Parameters + ---------- + self : object + DFN Class + num_poly : int + Number of fractures + + Returns + ------- + None + + Notes + ----- + None + + """ + frac_index = range(1, int(num_poly + 1)) + number_of_task = len(frac_index) + number_of_processes = self.ncpu + tasks_to_accomplish = mp.Queue() + tasks_that_are_done = mp.Queue() + processes = [] + + for i in range(number_of_task): + tasks_to_accomplish.put(i + 1) + + # Creating processes + for w in range(number_of_processes): + p = mp.Process(target=worker_interpolate, + args=(tasks_to_accomplish, tasks_that_are_done)) + processes.append(p) + p.start() + tasks_to_accomplish.put('STOP') + + for p in processes: + p.join() + + while not tasks_that_are_done.empty(): + print(tasks_that_are_done.get()) + + return True + + +def driver_parallel(self, num_poly): + """ This function drives the parallelization of the area sums upscaling. + + Parameters + ---------- + self : object + DFN Class + num_poly : int + Number of fractures + + Returns + ------- + None + + Notes + ----- + None + + """ + frac_index = range(1, int(num_poly + 1)) + number_of_task = len(frac_index) + number_of_processes = self.ncpu + tasks_to_accomplish = mp.Queue() + tasks_that_are_done = mp.Queue() + processes = [] + + for i in range(number_of_task): + tasks_to_accomplish.put(i + 1) + + # Creating processes + for w in range(number_of_processes): + p = mp.Process(target=worker, + args=(tasks_to_accomplish, tasks_that_are_done)) + processes.append(p) + p.start() + tasks_to_accomplish.put('STOP') + + for p in processes: + p.join() + + while not tasks_that_are_done.empty(): + print(tasks_that_are_done.get()) + + return True + + +def upscale_parallel(f_id): + """ Generates lagrit script that makes mesh files with area sums. + + Parameters + ---------- + f_id : int + Fracture index + + Returns + ------- + None + + Notes + ----- + None + + """ + fname = 'driver{0}.lgi'.format(f_id) + fin = "" + f = open(fname, 'w') + fin += """read / avs / ex_xyz{0}_2.inp / mo_vertex + cmo / addatt / mo_vertex / area_tri / vdouble / scalar / nnodes + cmo / readatt / mo_vertex / area_tri / 1 0 0 / ex_area{0}_2.table + + read / avs / frac{0}.inp / frac + cmo / addatt / frac / area_sum / vdouble / scalar / nnodes + + upscale / sum / frac, area_sum / 1 0 0 / mo_vertex, area_tri + + cmo / DELATT / frac / itp1 + cmo / DELATT / frac / icr1 + cmo / DELATT / frac / isn1 + cmo / DELATT / frac / dfield + + dump / avs / area_sum{0}.table / frac / 0 0 2 0 + + cmo / delete / mo_vertex + cmo / delete / frac + """.format(f_id) + fin += "finish" + #print(fin) + f.write(fin) + f.flush() + f.close() + + mh.run_lagrit_script( + f"driver{f_id}.lgi", + f"lagrit_logs/driver{f_id}", + ) + # Delete files + os.remove(f"ex_xyz{f_id}_2.inp") + os.remove(f"ex_area{f_id}_2.table") + os.remove(f"frac{f_id}.inp") + shutil.copy(f"driver{f_id}.lgi", "lagrit_scripts") + os.remove(f"driver{f_id}.lgi") + + +def worker(tasks_to_accomplish, tasks_that_are_done): + """ Worker function for python parallel. See multiprocessing module + documentation for details. + + Parameters + ---------- + tasks_to_accomplish : ? + Processes still in queue + tasks_that_are_done : ? + Processes complete + + Notes + ----- + None + + """ + try: + for f_id in iter(tasks_to_accomplish.get, 'STOP'): + upscale_parallel(f_id) + except: + pass + return True + + +def worker_interpolate(tasks_to_accomplish, tasks_that_are_done): + """ Worker function for python parallel. See multiprocessing module + documentation for details. + + Parameters + ---------- + tasks_to_accomplish : ? + Processes still in queue + tasks_that_are_done : ? + Processes complete + + Notes + ----- + None + + """ + try: + for f_id in iter(tasks_to_accomplish.get, 'STOP'): + interpolate_parallel(f_id) + except: + pass + return True + + +def interpolate_parallel(f_id): + mh.run_lagrit_script(f"driver_frac{f_id}.lgi", + f"lagrit_logs/driver_frac{f_id}") + shutil.copy(f"driver_frac{f_id}.lgi", "lagrit_scripts") + os.remove(f"driver_frac{f_id}.lgi") + + +def build_dict(self, num_poly, delete_files): + f_dict = {} + for i in range(1, num_poly + 1): + imts = np.genfromtxt(f"area_sum{i}.table", skip_header=4)[:, 0] + area_sums = np.genfromtxt(f"area_sum{i}.table", skip_header=4)[:, 1] + for j in range(len(imts)): + if int(float(imts[j])) != (num_poly + 1) and float( + area_sums[j]) > 0: + f_dict.setdefault(j + 1, []).append((i, float(area_sums[j]))) + if delete_files: + os.remove(f"area_sum{i}.table") + p_out = open("connections.p", "wb") + pickle.dump(f_dict, p_out, pickle.HIGHEST_PROTOCOL) + p_out.close() + + +def dir_cleanup(): + os.rename("build_octree.mlgi", "lagrit_scripts/build_octree.mlgi") + os.rename("driver_octree_start.lgi", + "lagrit_scripts/driver_octree_start.lgi") + os.rename("driver_octree_start.lgi.log", + "lagrit_logs/driver_octree_start.lgi.log") + os.rename("driver_octree_start.lgi.out", + "lagrit_logs/driver_octree_start.lgi.out") + os.rename("hex_to_tet.mlgi", "lagrit_scripts/hex_to_tet.mlgi") + os.rename("parameters_octree_dfn.mlgi", + "lagrit_scripts/parameters_octree_dfn.mlgi") + os.rename("remove_cells.mlgi", "lagrit_scripts/remove_cells.mlgi") + os.rename("intersect_refine.mlgi", "lagrit_scripts/intersect_refine.mlgi") + os.rename("intersect_refine_np1.mlgi", + "lagrit_scripts/intersect_refine_np1.mlgi") + os.remove("mohex2.inp") + os.remove("MOTET.inp") + os.remove("MOTET_np1.inp") +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/udfm/upscale.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/udfm/upscale.html new file mode 100644 index 000000000..31d1028b5 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/meshing/udfm/upscale.html @@ -0,0 +1,394 @@ + + + + + + pydfnworks.dfnGen.meshing.udfm.upscale — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for pydfnworks.dfnGen.meshing.udfm.upscale

+"""
+.. module:: upscale.py
+   :synopsis: Generates PFLOTRAN or FEHM input from octree refined continuum mesh
+.. moduleauthor:: Matthew Sweeney <msweeney2796@lanl.gov>
+
+"""
+
+import os
+import numpy as np
+import sys
+import subprocess
+import shutil
+import h5py
+import time
+import math as m
+import glob
+import pickle
+
+
+
+[docs] +def upscale(self, mat_perm, mat_por, path='../'): + """ Generate permeabilities and porosities based on output of map2continuum. + + Parameters + ---------- + self : object + DFN Class + mat_perm : float + Matrix permeability (in m^2) + mat_por: float + Matrix porosity + + Returns + ------- + perm_fehm.dat : text file + Contains permeability data for FEHM input + rock_fehm.dat : text file + Contains rock properties data for FEHM input + mesh_permeability.h5 : h5 file + Contains permeabilites at each node for PFLOTRAN input + mesh_porosity.h5 : h5 file + Contains porosities at each node for PFLOTRAN input + + Notes + ----- + None + + """ + + print('=' * 80) + print("Generating permeability and porosity for octree mesh: Starting") + print('=' * 80) + + # Check values of porosity and permeability + if mat_por < 0 or mat_por > 1: + error = "Matrix porosity must be between 0 and 1. Exiting\n" + sys.stderr.write(error) + sys.exit(1) + + if self.flow_solver == "FEHM": + with open("perm_fehm.dat", "w") as f: + f.write("perm\n") + with open("rock_fehm.dat", "w") as g: + g.write("rock\n") + + # Bring in f_dict dictionary + f_dict = pickle.load(open("connections.p", "rb")) + + with open('full_mesh.uge') as f: + num_nodes = int(f.readline().strip().split()[1]) + cv_vol = np.zeros(num_nodes, 'float') + iarray = np.zeros(num_nodes, '=i4') + for i in range(num_nodes): + fline = f.readline().strip().split() + cv_vol[i] = float(fline[4]) + iarray[i] = int(fline[0]) + + perm_var = np.zeros(num_nodes, 'float') + por_var = np.zeros(num_nodes, 'float') + #cv_vol = np.zeros(num_nodes, 'float') + #iarray = np.zeros(num_nodes, '=i4') + frac_vol = np.zeros(num_nodes, 'float') + permX = np.zeros(num_nodes, 'float') + permY = np.zeros(num_nodes, 'float') + permZ = np.zeros(num_nodes, 'float') + + # Populate permeability and porosity arrays here + for i in range(1, num_nodes + 1): + if i in f_dict: + # Get porosity: + for j in range(len(f_dict[i])): + # Calculate total volume of fractures in cv cell i + frac_vol[i - 1] += self.aperture[f_dict[i][j][0] - + 1] * f_dict[i][j][1] + por_var[i - 1] = frac_vol[i - 1] / cv_vol[i - 1] + if por_var[i - 1] == 0: + por_var[i - 1] = mat_por + if por_var[i - 1] > 1.0: + por_var[i - 1] = 1.0 + + # Get permeability: + perm_tensor = np.zeros([3, 3]) + phi_sum = 0 + for j in range(len(f_dict[i])): + phi = (self.aperture[f_dict[i][j][0] - 1] * + f_dict[i][j][1]) / cv_vol[i - 1] + if phi > 1.0: + phi = 1.0 + phi_sum += phi + if phi_sum > 1.0: + phi_sum = 1.0 + b = self.aperture[f_dict[i][j][0] - 1] + # Construct tensor Omega + Omega = np.zeros([3, 3]) + n1 = self.normal_vectors[f_dict[i][j][0] - 1][0] + n2 = self.normal_vectors[f_dict[i][j][0] - 1][1] + n3 = self.normal_vectors[f_dict[i][j][0] - 1][2] + Omega[0][0] = (n2)**2 + (n3)**2 + Omega[0][1] = -n1 * n2 + Omega[0][2] = -n3 * n1 + Omega[1][0] = -n1 * n2 + Omega[1][1] = (n3)**2 + (n1)**2 + Omega[1][2] = -n2 * n3 + Omega[2][0] = -n3 * n1 + Omega[2][1] = -n2 * n3 + Omega[2][2] = (n1)**2 + (n2)**2 + perm_tensor += (phi * (b)**2 * Omega) + perm_tensor *= 1. / 12 + + # Calculate eigenvalues + permX[i - 1] = np.linalg.eigvals(perm_tensor)[0] + permY[i - 1] = np.linalg.eigvals(perm_tensor)[1] + permZ[i - 1] = np.linalg.eigvals(perm_tensor)[2] + + # Arithmetic average of matrix perm + permX[i - 1] += (1 - phi_sum) * mat_perm + permY[i - 1] += (1 - phi_sum) * mat_perm + permZ[i - 1] += (1 - phi_sum) * mat_perm + + # Correction factor + + # Actual value doesn't matter here, just needs to be high + min_n1 = 1e6 + min_n2 = 1e6 + min_n3 = 1e6 + + # See Sweeney et al. 2019 Computational Geoscience + for j in range(len(f_dict[i])): + n1_temp = self.normal_vectors[f_dict[i][j][0] - 1][0] + theta1_t = m.degrees(m.acos(n1_temp)) % 90 + if abs(theta1_t - 45) <= min_n1: + theta1 = theta1_t + min_n1 = theta1_t + n2_temp = self.normal_vectors[f_dict[i][j][0] - 1][1] + theta2_t = m.degrees(m.acos(n2_temp)) % 90 + if abs(theta2_t - 45) <= min_n2: + theta2 = theta2_t + min_n2 = theta2_t + n3_temp = self.normal_vectors[f_dict[i][j][0] - 1][2] + theta3_t = m.degrees(m.acos(n3_temp)) % 90 + if abs(theta3_t - 45) <= min_n3: + theta3 = theta3_t + min_n3 = theta3_t + + sl = (2 * 2**(1. / 2) - 1) / -45.0 + b = 2 * 2**(1. / 2) + + cf_x = sl * abs(theta1 - 45) + b + cf_y = sl * abs(theta2 - 45) + b + cf_z = sl * abs(theta3 - 45) + b + + permX[i - 1] *= cf_x + permY[i - 1] *= cf_y + permZ[i - 1] *= cf_z + + perm_var[i - 1] = max(permX[i - 1], permY[i - 1], permZ[i - 1]) + else: + # Assign matrix properties + por_var[i - 1] = mat_por + perm_var[i - 1] = mat_perm + + # Note these aren't needed if not using anisotropic perm + permX[i - 1] = mat_perm + permY[i - 1] = mat_perm + permZ[i - 1] = mat_perm + + if self.flow_solver == "FEHM": + with open("perm_fehm.dat", "a") as f: + f.write( + str(i) + " " + str(i) + " " + "1" + " " + + str(perm_var[i - 1]) + " " + str(perm_var[i - 1]) + " " + + str(perm_var[i - 1]) + "\n") + with open("rock_fehm.dat", "a") as g: + g.write( + str(i) + " " + str(i) + " " + "1" + " " + "2165." + " " + + "931." + " " + str(por_var[i - 1]) + "\n") + + # Need an extra space at end for FEHM + if self.flow_solver == "FEHM": + with open("perm_fehm.dat", "a") as f: + f.write("\n") + with open("rock_fehm.dat", "a") as g: + g.write("\n") + + if self.flow_solver == "PFLOTRAN": + perm_filename = 'mesh_permeability.h5' + poros_filename = 'mesh_porosity.h5' + + h5file = h5py.File(perm_filename, mode='w') + dataset_name = 'Cell Ids' + h5dset = h5file.create_dataset(dataset_name, data=iarray) + + dataset_name = 'Permeability' + h5dset = h5file.create_dataset(dataset_name, data=perm_var) + + #dataset_name = 'Perm_X' + #h5dset = h5file.create_dataset(dataset_name, data = permX) + + #dataset_name = 'Perm_Y' + #h5set = h5file.create_dataset(dataset_name, data = permY) + + #dataset_name = 'Perm_Z' + #h5set = h5file.create_dataset(dataset_name, data = permZ) + h5file.close() + + h5file = h5py.File(poros_filename, mode='w') + dataset_name = 'Cell Ids' + h5dset = h5file.create_dataset(dataset_name, data=iarray) + + dataset_name = 'Porosity' + h5dset = h5file.create_dataset(dataset_name, data=por_var) + h5file.close() + + + #upscale_cleanup() + + # What nodes are fractures vs. matrix + tag = perm_var > mat_perm + tag = tag.astype("uint8") + # Add 1 since PFLOTRAN doesn't like mat id = 0 + tag += 1 + np.savetxt("tag_frac.dat", tag, '%d', delimiter=",") + if self.flow_solver == "PFLOTRAN": + # Save as h5 + h5file = h5py.File("materials.h5", mode="w") + dataset_name = 'Materials/Cell Ids' + h5dset = h5file.create_dataset(dataset_name, data=iarray) + + dataset_name = 'Materials/Material Ids' + h5dset = h5file.create_dataset(dataset_name, data=tag) + h5file.close() + + + if self.flow_solver == "PFLOTRAN": + self.uge_file = "full_mesh.uge" + elif self.flow_solver == "FEHM": + self.uge_file = "full_mesh.stor" + + print('=' * 80) + print("Generating permeability and porosity for octree mesh: Finished") + print('=' * 80)
+ + + +#def upscale_cleanup(): +# files_to_remove = [ +# "area*", "build*", "driver*", "ex*", "frac*", "hex*", "intersect*", +# "log*", "out*", "parame*", "remove*", "time*", "tmp*" +# ] +# for name in files_to_remove: +# for fl in glob.glob(name): +# os.remove(fl) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/well_package/wells.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/well_package/wells.html new file mode 100644 index 000000000..8b875de4e --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGen/well_package/wells.html @@ -0,0 +1,1369 @@ + + + + + + pydfnworks.dfnGen.well_package.wells — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for pydfnworks.dfnGen.well_package.wells

+import os
+import numpy as np
+import shutil
+
+from pydfnworks.dfnGen.meshing.mesh_dfn import mesh_dfn_helper as mh
+
+
+[docs] +def tag_well_in_mesh(self, wells): + """ Identifies nodes in a DFN for nodes the intersect a well with radius r [m]\n + 1. Well coordinates in well["filename"] are converted to a polyline that are written into "well_{well['name']}_line.inp"\n + 2. Well is expanded to a volume with radius well["r"] and written into the avs file well_{well["name"]}_volume.inp\n + 3. Nodes in the DFN that intersect with the well are written into the zone file well_{well["name"]}.zone\n + 4. If using PFLOTRAN, then an ex file is created from the well zone file\n + + Parameters + ----------- + self : object + DFN Class + well: Dictionary + Dictionary of information about the well that contains the following attributes + + well["name"] : string + name of the well + + well["filename"] : string + filename of the well coordinates with the following format + x0 y0 z0\n + x1 y1 z1\n + ...\n + xn yn zn\n + + well["r"] : float + radius of the well + Returns + -------- + None + Notes + -------- + Wells can be a list of well dictionaries + + """ + + if type(wells) is dict: + well = wells + print( + f"\n\n--> Identifying nodes in the DFN intersecting with a vertical well named {well['name']}." + ) + + # 1) convert well into polyline AVS if it doesn't exist + if not os.path.isfile(f"well_{well['name']}_line.inp"): + convert_well_to_polyline_avs(well) + + # 2) expand the polyline of the well into a volume with radius r + self.expand_well(well) + + # 3) find the nodes in the well that corresponds / intersect the well + get_well_zone(well, self.inp_file) + + # 4) convert the zone file to ex files for PFLTORAN + if self.flow_solver == "PFLOTRAN": + self.zone2ex(zone_file=f"well_{well['name']}.zone", face='well') + + if self.flow_solver == "FEHM": + print(f"--> Well nodes are in well_{well['name']}.zone") + + print(f"--> Well creation for {well['name']} complete\n\n") + + if type(wells) is list: + for well in wells: + print( + f"\n\n--> Identifying nodes in the DFN intersecting with a vertical well named {well['name']}." + ) + + # 1) convert well into polyline AVS if it doesn't exist + if not os.path.isfile(f"well_{well['name']}_line.inp"): + convert_well_to_polyline_avs(well) + + # 2) expand the polyline of the well into a volume with radius r + self.expand_well(well) + + # 3) find the nodes in the well that corresponds / intersect the well + get_well_zone(well, self.inp_file) + + # 4) convert the zone file to ex files for PFLTORAN + if self.flow_solver == "PFLOTRAN": + self.zone2ex(zone_file=f"well_{well['name']}.zone", + face='well') + + if self.flow_solver == "FEHM": + print(f"--> Well nodes are in well_{well['name']}.zone") + + print(f"--> Well creation for {well['name']} complete\n\n")
+ + + +def convert_well_to_polyline_avs(well, radius): + """ Identifies converts well coordinates into a polyline avs file. Distance between + point on the polyline are h/2 apart. Polyline is written into "well_{well['name']}_line.inp" + + Parameters + ----------- + well: dictionary of information about the well. Contains the following: + + well["name"] : string + name of the well + + well["filename"] : string + filename of the well coordinates. "well_coords.dat" for example. + Format is : + x0 y0 z0 + x1 y1 z1 + ... + xn yn zn + + well["r"] : float + radius of the well + + h : float + h parameter for meshing. + + Returns + -------- + None + + Notes + -------- + If flow solver is set to PFLOTRAN, the zone file dumped by LaGriT will be converted to + an ex file. + + """ + print("--> Interpolating well coordinates into a polyline") + + + # read in well coordinates + print(well['filename']) + pts = np.genfromtxt(f"{well['filename']}") + n, _ = np.shape(pts) + + # Linear interpolation of well into a polyline + new_pts = [] + new_pts.append(pts[0]) + new_idx = 0 + + for i in range(1, n): + distance = np.linalg.norm(pts[i, :] - pts[i - 1, :]) + if distance < radius: + new_pts.append(pts[i, :]) + new_idx += 1 + else: + # discretized to less than h + m = int(np.ceil(distance / radius)) + dx = (pts[i, 0] - pts[i - 1, 0]) / m + dy = (pts[i, 1] - pts[i - 1, 1]) / m + dz = (pts[i, 2] - pts[i - 1, 2]) / m + for j in range(m): + interp = np.zeros(3) + interp[0] = new_pts[new_idx][0] + dx + interp[1] = new_pts[new_idx][1] + dy + interp[2] = new_pts[new_idx][2] + dz + new_pts.append(interp) + del interp + new_idx += 1 + + print("--> Interpolating well coordinates into a polyline: Complete") + # Write interpolated polyline into an AVS file + avs_filename = f"well_{well['name']}_line.inp" + print(f"--> Writing polyline into avs file : {avs_filename}") + + num_pts = new_idx + 1 + pt_digits = len(str(num_pts)) + + num_elem = new_idx + elem_digits = len(str(num_elem)) + + favs = open(avs_filename, "w") + favs.write(f"{num_pts}\t{num_elem}\t0\t0\t0\n") + for i in range(num_pts): + favs.write( + f"{i+1:0{pt_digits}d} {new_pts[i][0]:12e} {new_pts[i][1]:12e} {new_pts[i][2]:12e}\n" + ) + for i in range(num_elem): + favs.write(f"{i+1} 1 line {i+1} {i+2}\n") + favs.close() + print(f"--> Writing polyline into avs file : {avs_filename} : Complete") + + +def expand_well(self,well): + """ Expands the polyline defining the well into a volume with radius r [m]. + A sphere of points around each point is created and then connected. + Volume is written into the avs file well_{well["name"]}_volume.inp + + Parameters + ----------- + well: + dictionary of information about the well. Contains the following: + + well["name"] : string + name of the well + + well["filename"] : string + filename of the well coordinates. "well_coords.dat" for example. + Format is : + x0 y0 z0 + x1 y1 z1 + ... + xn yn zn + + well["r"] : float + radius of the well + + Returns + -------- + None + + Notes + -------- + Mesh of the well is written into the avs file {well["name"][:-4]}.inp + + """ + + print("--> Expanding well into a volume.") + + r = well["r"] + + convert_well_to_polyline_avs(well, r) + + angle_r = r / np.sqrt(2) + + lagrit_script = f""" + ## read in polyline of well + read / well_{well['name']}_line.inp / mo_line + cmo / printatt / mo_line / -xyz- / minmax + + ## expand every point in the polyline into a discrete sphere + ## with radius r + cmo / create / mo_well / / / tet + copypts / mo_well / mo_line + + cmo / create / mo_tmp / / / line + copypts / mo_tmp / mo_line + cmo / select / mo_tmp + trans / 1 0 0 / 0. 0. 0. / {well["r"]} 0 0 + copypts / mo_well / mo_tmp + cmo / delete / mo_tmp + + cmo / create / mo_tmp / / / line + copypts / mo_tmp / mo_line + cmo / select / mo_tmp + trans / 1 0 0 / 0. 0. 0. / -{well["r"]} 0 0 + copypts / mo_well / mo_tmp + cmo / delete / mo_tmp + + cmo / create / mo_tmp / / / line + copypts / mo_tmp / mo_line + cmo / select / mo_tmp + trans / 1 0 0 / 0. 0. 0. / 0 {well["r"]} 0 + copypts / mo_well / mo_tmp + cmo / delete / mo_tmp + + cmo / create / mo_tmp / / / line + copypts / mo_tmp / mo_line + cmo / select / mo_tmp + trans / 1 0 0 / 0. 0. 0. / 0 -{well["r"]} 0 + copypts / mo_well / mo_tmp + cmo / delete / mo_tmp + + cmo / create / mo_tmp / / / line + copypts / mo_tmp / mo_line + cmo / select / mo_tmp + trans / 1 0 0 / 0. 0. 0. / 0 0 {well["r"]} + copypts / mo_well / mo_tmp + cmo / delete / mo_tmp + + cmo / create / mo_tmp / / / line + copypts / mo_tmp / mo_line + cmo / select / mo_tmp + trans / 1 0 0 / 0. 0. 0. / 0 0 -{well["r"]} + copypts / mo_well / mo_tmp + cmo / delete / mo_tmp + + cmo / create / mo_tmp / / / line + copypts / mo_tmp / mo_line + cmo / select / mo_tmp + trans / 1 0 0 / 0. 0. 0. / {angle_r} {angle_r} 0 + copypts / mo_well / mo_tmp + cmo / delete / mo_tmp + + cmo / create / mo_tmp / / / line + copypts / mo_tmp / mo_line + cmo / select / mo_tmp + trans / 1 0 0 / 0. 0. 0. / {angle_r} -{angle_r} 0 + copypts / mo_well / mo_tmp + cmo / delete / mo_tmp + + cmo / create / mo_tmp / / / line + copypts / mo_tmp / mo_line + cmo / select / mo_tmp + trans / 1 0 0 / 0. 0. 0. / -{angle_r} {angle_r} 0 + copypts / mo_well / mo_tmp + cmo / delete / mo_tmp + + cmo / create / mo_tmp / / / line + copypts / mo_tmp / mo_line + cmo / select / mo_tmp + trans / 1 0 0 / 0. 0. 0. / -{angle_r} -{angle_r} 0 + copypts / mo_well / mo_tmp + cmo / delete / mo_tmp + + cmo / create / mo_tmp / / / line + copypts / mo_tmp / mo_line + cmo / select / mo_tmp + trans / 1 0 0 / 0. 0. 0. / 0 {angle_r} {angle_r} + copypts / mo_well / mo_tmp + cmo / delete / mo_tmp + + cmo / create / mo_tmp / / / line + copypts / mo_tmp / mo_line + cmo / select / mo_tmp + trans / 1 0 0 / 0. 0. 0. / 0 {angle_r} -{angle_r} + copypts / mo_well / mo_tmp + cmo / delete / mo_tmp + + cmo / create / mo_tmp / / / line + copypts / mo_tmp / mo_line + cmo / select / mo_tmp + trans / 1 0 0 / 0. 0. 0. / 0 -{angle_r} {angle_r} + copypts / mo_well / mo_tmp + cmo / delete / mo_tmp + + cmo / create / mo_tmp / / / line + copypts / mo_tmp / mo_line + cmo / select / mo_tmp + trans / 1 0 0 / 0. 0. 0. / 0 -{angle_r} -{angle_r} + copypts / mo_well / mo_tmp + cmo / delete / mo_tmp + + cmo / create / mo_tmp / / / line + copypts / mo_tmp / mo_line + cmo / select / mo_tmp + trans / 1 0 0 / 0. 0. 0. / {angle_r} 0 {angle_r} + copypts / mo_well / mo_tmp + cmo / delete / mo_tmp + + cmo / create / mo_tmp / / / line + copypts / mo_tmp / mo_line + cmo / select / mo_tmp + trans / 1 0 0 / 0. 0. 0. / {angle_r} 0 -{angle_r} + copypts / mo_well / mo_tmp + cmo / delete / mo_tmp + + cmo / create / mo_tmp / / / line + copypts / mo_tmp / mo_line + cmo / select / mo_tmp + trans / 1 0 0 / 0. 0. 0. / -{angle_r} 0 {angle_r} + copypts / mo_well / mo_tmp + cmo / delete / mo_tmp + + cmo / create / mo_tmp / / / line + copypts / mo_tmp / mo_line + cmo / select / mo_tmp + trans / 1 0 0 / 0. 0. 0. / -{angle_r} 0 -{angle_r} + copypts / mo_well / mo_tmp + cmo / delete / mo_tmp + + ## Could add more permutations, but this looks good enough right now + ## JDH 9 Sept. 2020 + + ################## DEBUG ########################### + # dump / well_pts.inp / mo_well + ################## DEBUG ########################### + + # filter out point that are too close + cmo / select / mo_well + filter / 1 0 0 / {0.1*r} + rmpoint / compress + cmo / setatt / mo_well / imt / 1 0 0 / 1 + + # connect the point cloud and make a volume mesh + connect / delaunay + resetpts / itp + + ################## DEBUG ########################### + # dump / well_{well["name"]}.inp / mo_well + ################## DEBUG ########################### + + # add edge_max attribute and remove elements with big edges + quality / edge_max / y + eltset /big/ edgemax / gt / {np.sqrt(2)*r} + cmo / setatt / mo_well / itetclr / eltset, get, big / 2 + rmmat / 2 + rmpoint / compress + + dump / well_{well["name"]}_volume.inp / mo_well + + ################## DEBUG ########################### + # # extract the surface of the well + # # This is done to remove internal points and reduce + # # the total number of elements in the mesh + # # This speeds up the intersection checking later on + # # I couldn't get this to work in a robust way. + # # There were some weird LaGriT errors if I deleted + # # mesh object. + # # Works if we stop before this, but I'm leaving it to + # # revisit if need be. + # # JDH 10/9/2020 + + # extract / surfmesh / 1,0,0 /mo_shell / mo_well + # cmo / select / mo_shell + # cmo / delete / mo_well + + # ################## DEBUG ########################### + # dump / well_{well["name"]}_shell.inp / mo_shell + # ################## DEBUG ########################### + + # # Copy the surface of the well into a tet mesh + # cmo / create / mo_well2 / / / tet + # copypts / mo_well2 / mo_shell + # cmo / select / mo_well2 + # # cmo / delete / mo_shell + + # # filter out point that are too close + # filter / 1 0 0 / {0.1*r} + # rmpoint / compress + # cmo / setatt / mo_well2 / imt / 1 0 0 / 1 + + # # connect the point cloud and make a volume mesh + # connect / delaunay + # resetpts / itp + + # # add edge_max attribute and remove elements with big edges + # quality / edge_max / y + # eltset /big/ edgemax / gt / {np.sqrt(2)*r} + # cmo / setatt / mo_well2 / itetclr / eltset, get, big / 2 + # rmmat / 2 + # rmpoint / compress + + # # write out final well mesh + # dump / well_{well["name"]}_volume.inp / mo_well2 + + finish + + """ + # Write LaGriT commands to file + with open(f"expand_well_{well['name']}.lgi", "w") as fp: + fp.write(lagrit_script) + fp.flush() + + # Execute LaGriT + mh.run_lagrit_script(f"expand_well_{well['name']}.lgi", + output_file=f"expand_well_{well['name']}", + quiet=False) + + print("--> Expanding well complete.") + + +def get_well_zone(well, inp_file): + """Identifies nodes in a DFN for nodes the intersect a well with radius r [m] + First, all elements that intersect the well are identified. + Second, all nodes of those elements are tagged. + Third, that collection of nodes are dumped as a zone file (well_{well["name"]}.zone) + + Parameters + ----------- + self : object + DFN Class + well: + dictionary of information about the well. Contains the following: + + well["name"] : string + name of the well + + well["filename"] : string + filename of the well coordinates. "well_coords.dat" for example. + File format: + x0 y0 z0 + x1 y1 z1 + ... + xn yn zn + + well["r"] : float + radius of the well + + Returns + -------- + None + + Notes + -------- + None + + """ + # # if the well has not been converted to AVS, do that first + # if not os.path.isfile(f"well_{well['name']}_line.inp"): + # convert_well_to_polyline_avs(well,h) + # # if the well has not been expanded + # if not os.path.isfile(f"well_{well['name']}_volume.inp"): + # expand_well(well) + + lagrit_script = f""" + +# read in well volume +read / well_{well["name"]}_volume.inp / mo_well + +# read in DFN +read / {inp_file} / mo_dfn + +# find intersecting cells +cmo / select / mo_dfn +intersect_elements / mo_dfn / mo_well / well_{well["name"]}_inter + +eltset / ewell / well_{well["name"]}_inter / gt / 0 + +# dump dfn mesh with intersections tagged +#dump / avs / {inp_file[:-3]}_tagged.inp / mo_dfn + +# gather nodes of intersecting cells +pset / well_{well["name"]} / eltset / ewell + +# dump nodes from intersecting cells +pset / well_{well["name"]} / zone / well_{well["name"]}.zone + +finish + +""" + # Write LaGriT commands to file + with open(f"get_well_{well['name']}_zone.lgi", "w") as fp: + fp.write(lagrit_script) + fp.flush() + + # Execute LaGriT + mh.run_lagrit_script(f"get_well_{well['name']}_zone.lgi", + output_file=f"create_well_{well['name']}", + quiet=False) + + with open(f"well_{well['name']}.zone", "r") as fp: + number_of_nodes = int(fp.readlines()[3]) + if number_of_nodes > 0: + print(f"--> There are {number_of_nodes} nodes in the well zone") + else: + print("--> WARNING!!! The well did not intersect the DFN!!!") + + +
+[docs] +def find_well_intersection_points(self, wells): + """ Identifies points on a DFN where the well intersects the network. + These points are used in meshing the network to have higher resolution in the mesh in these points. + Calls a sub-routine run_find_well_intersection_points. + + Parameters + ----------- + self : object + DFN Class + well: + dictionary of information about the well. Contains the following: + + well["name"] : string + name of the well + + well["filename"] : string + filename of the well coordinates. "well_coords.dat" for example. + Format is : + x0 y0 z0 + x1 y1 z1 + ... + xn yn zn + + well["r"] : float + radius of the well + + Returns + -------- + None + + Notes + -------- + Wells can be a list of well dictionaries. + Calls the subroutine run_find_well_intersection_points to remove redundant code. + + """ + # check for reduced mesh, if it doesn't exists, make it + print("--> Checking for reduced_mesh.inp") + if not os.path.isfile("reduced_mesh.inp"): + print("--> reduced_mesh.inp not found. Creating it now.") + self.mesh_network() + else: + print("--> reduced_mesh.inp found. Moving on.") + + # if using a single well + if type(wells) is dict: + self.run_find_well_intersection_points(wells) + # using a list of wells, loop over them. + elif type(wells) is list: + for well in wells: + self.run_find_well_intersection_points(well) + + # Run cross check + cross_check_pts(self.h)
+ + + +def run_find_well_intersection_points(self, well): + """ Runs the workflow for finding the point of intersection of the DFN with the well. + + Parameters + ----------- + well: + dictionary of information about the well. Contains the following: + + well["name"] : string + name of the well + + well["filename"] : string + filename of the well coordinates. "well_coords.dat" for example. + Format is : + x0 y0 z0 + x1 y1 z1 + ... + xn yn zn + + well["r"] : float + radius of the well + h : float + Minimum h length scale in the network + + Returns + -------- + None + + Notes + -------- + This function was designed to minimize redundancy in the workflow. It's called + within find_well_intersection_points() + """ + + print(f"\n\n--> Working on well {well['name']}") + + # 1) convert well into polyline AVS + if not os.path.isfile(f"well_{well['name']}_line.inp"): + convert_well_to_polyline_avs(well, self.h) + + # run LaGriT scripts to dump information + find_segments(well) + + self.well_point_of_intersection(well) + + +def find_segments(well): + """ LaGriT script to identify the points of intersection between the DFN and the well. + + Parameters + ----------- + well: + dictionary of information about the well. Contains the following: + + well["name"] : string + name of the well + + well["filename"] : string + filename of the well coordinates. "well_coords.dat" for example. + Format is : + x0 y0 z0 + x1 y1 z1 + ... + xn yn zn + + well["r"] : float + radius of the well + + Returns + -------- + None + + Notes + -------- + points of intersection are written into the avs file well_{well['name']}_intersect.inp + + OUTPUT: well_segments_intersect.inp is a subset of the well line segments that intersect fractures. + The segments are tagged so itetclr and imt are set to the value of the fracture they intersect. + """ + + lagrit_script = f""" +# +# OUTPUT: intersected_fracture.list tells you the list of fractures intersected by the well. +# OUTPUT: well_segments_intersect.inp is a subset of the well line segments that intersect fractures. +# The segments are tagged so itetclr and imt are set to the value of the fracture they intersect. +# +define / INPUT_DFN / reduced_mesh.inp +define / INPUT_WELL / well_{well['name']}_line.inp +define / OUTPUT_WELL_SEGMENTS / well_{well['name']}_intersect.inp +# define / OUTPUT_FRACTURE_LIST / {well['name']}_fracture.list +# +read / avs / INPUT_DFN / mo_tri +read / avs / INPUT_WELL / mo_line +# +# Find the triangles of the DFN mesh that intersect the well lines. +# Get rid of all the non-intersecting triangles. +# +intersect_elements / mo_tri / mo_line / if_intersect +eltset / e_not_intersect / if_intersect / eq / 0 +rmpoint / element / eltset get e_not_intersect +rmpoint / compress +cmo / DELATT / mo_tri / if_intersect +# +# dump / avs / reduced_reduced_mesh.inp / mo_tri +cmo / addatt / mo_tri / id_fracture / vint / scalar / nelements +cmo / copyatt / mo_tri / mo_tri / id_fracture / itetclr +# dump / avs / OUTPUT_FRACTURE_LIST / mo_tri / 0 0 0 1 +# +# Find the segments of the well (line object) that intersect the fracture planes (triangles) +# +intersect_elements / mo_line / mo_tri / if_intersect +eltset / e_not_intersect / if_intersect / eq / 0 +rmpoint / element / eltset get e_not_intersect +rmpoint / compress +cmo / DELATT / mo_line / if_intersect +# BEGIN DEBUG +# dump / avs / OUTPUT_WELL_SEGMENTS / mo_line +# END DEBUG +# +# Reduce the size of the triangles so interpolation works. +# +cmo / select / mo_tri +# Refine 2**7 128 +refine2d +intersect_elements / mo_tri / mo_line / if_intersect +eltset / e_not_intersect / if_intersect / eq / 0 +rmpoint / element / eltset get e_not_intersect +rmpoint / compress +cmo / DELATT / mo_tri / if_intersect + +refine2d +intersect_elements / mo_tri / mo_line / if_intersect +eltset / e_not_intersect / if_intersect / eq / 0 +rmpoint / element / eltset get e_not_intersect +rmpoint / compress +cmo / DELATT / mo_tri / if_intersect + +refine2d +intersect_elements / mo_tri / mo_line / if_intersect +eltset / e_not_intersect / if_intersect / eq / 0 +rmpoint / element / eltset get e_not_intersect +rmpoint / compress +cmo / DELATT / mo_tri / if_intersect + +refine2d +intersect_elements / mo_tri / mo_line / if_intersect +eltset / e_not_intersect / if_intersect / eq / 0 +rmpoint / element / eltset get e_not_intersect +rmpoint / compress +cmo / DELATT / mo_tri / if_intersect + +refine2d +intersect_elements / mo_tri / mo_line / if_intersect +eltset / e_not_intersect / if_intersect / eq / 0 +rmpoint / element / eltset get e_not_intersect +rmpoint / compress +cmo / DELATT / mo_tri / if_intersect + +refine2d +intersect_elements / mo_tri / mo_line / if_intersect +eltset / e_not_intersect / if_intersect / eq / 0 +rmpoint / element / eltset get e_not_intersect +rmpoint / compress +cmo / DELATT / mo_tri / if_intersect + +refine2d +intersect_elements / mo_tri / mo_line / if_intersect +eltset / e_not_intersect / if_intersect / eq / 0 +rmpoint / element / eltset get e_not_intersect +rmpoint / compress +cmo / DELATT / mo_tri / if_intersect + +# BEGIN DEBUG +# dump / avs / tmp_refine.inp / mo_tri +# END DEBUG + +interpolate / voronoi / mo_line itetclr / 1 0 0 / mo_tri imt +interpolate / voronoi / mo_line imt / 1 0 0 / mo_tri imt + +cmo / modatt / mo_line / itp / ioflag / l +cmo / modatt / mo_line / icr / ioflag / l +cmo / modatt / mo_line / isn / ioflag / l + +dump / avs / OUTPUT_WELL_SEGMENTS / mo_line + +finish + + +""" + # Write LaGriT commands to file + with open(f"find_well_{well['name']}_segment.lgi", "w") as fp: + fp.write(lagrit_script) + fp.flush() + + # Execute LaGriT + mh.run_lagrit_script(f"find_well_{well['name']}_segment.lgi", + output_file=f"find_well_{well['name']}_segment", + quiet=False) + + +def well_point_of_intersection(self, well): + """ Takes the well points found using find_segments and projects the points onto the fracture plane. These points are written into well_points.dat file. During meshing, these points are read in and a higher resolution mesh is created near by them. well_points.dat has the format + + fracture_id x y z + ... + + for every intersection point. + + Parameters + ----------- + well: + dictionary of information about the well. Contains the following: + + well["name"] : string + name of the well + + well["filename"] : string + filename of the well coordinates. "well_coords.dat" for example. + Format is : + x0 y0 z0 + x1 y1 z1 + ... + xn yn zn + + well["r"] : float + radius of the well + + Returns + -------- + None + + Notes + -------- + + """ + + print(f"--> Finding well points on DFN for {well['name']}") + # create file to keep well points if it doesn't exist. Otherwise set to append. + if not os.path.isfile("well_points.dat"): + fwell = open("well_points.dat", "w") + fwell.write("fracture_id x y z\n") + else: + fwell = open("well_points.dat", "a") + + well_line_file = f"well_{well['name']}_intersect.inp" + + pts, elems, fracture_list = get_segments(well_line_file) + + if len(fracture_list) == 0: + print( + f"\n--> Warning. The well {well['name']} did not intersect the DFN!!!\n" + ) + + points = self.gather_points() + for elem in elems: # Parameterize the line center of the well + l0 = np.zeros(3) + l0[0] = pts[elem["pt1"] - 1]["x"] + l0[1] = pts[elem["pt1"] - 1]["y"] + l0[2] = pts[elem["pt1"] - 1]["z"] + l1 = np.zeros(3) + l1[0] = pts[elem["pt2"] - 1]["x"] + l1[1] = pts[elem["pt2"] - 1]["y"] + l1[2] = pts[elem["pt2"] - 1]["z"] + l = l1 - l0 + + fracture_id = elem["frac"] + # get the plane on which the fracture lies + n = self.normal_vectors[fracture_id - 1, :] + p0 = points[fracture_id - 1, :] + # p0 = get_center(fracture_id) + R = rotation_matrix(n, [0, 0, 1]) + + # find the point of intersection between the well line and the plane + d = np.dot((p0 - l0), n) / (np.dot(l, n)) + p = l0 + l * d + v = rotate_point(p, R) + fwell.write(f"{fracture_id} {v[0]} {v[1]} {v[2]}\n") + fwell.close() + + +def cross_check_pts(h): + """ Sometimes multiple points of intersection are identified on the same fracture. This can occur if the discretized well has points close to the fracture plane. This function walks through well_points.dat and removes duplicate points that are within h of one another and on the same fracture plane. + + + Parameters + ----------- + h : float + Minimum length scale in the network. + + Returns + -------- + None + + Notes + -------- + None + """ + + print("\n--> Cross Checking well points") + pts = np.genfromtxt("well_points.dat", skip_header=1) + num_pts, _ = np.shape(pts) + + # Walk through well points and see if they are too close together, + # This can happen due to machine precision in LaGriT. + # We only keep 1 point per fracture per well. + remove_idx = [] + for i in range(num_pts): + fracture_number = pts[i, 0] + for j in range(i + 1, num_pts): + # Check if points are on the same fracture to reduce number of distance checks + if fracture_number == pts[j, 0]: + dist = abs(pts[i, 1] - pts[j, 1]) + abs( + pts[i, 2] - pts[j, 2]) + abs(pts[i, 3] - pts[j, 3]) + # if the points are closure that h/2, mark one to be removed. + if dist < h / 2: + remove_idx.append(j) + + # Find the id of those points to keep + keep_pt_indes = list(set(range(num_pts)) - set(remove_idx)) + # keep only those points + pts = pts[keep_pt_indes] + num_pts = len(pts) + # write to file + # os.remove("well_points.dat") + with open("well_points.dat", "w") as fwell: + fwell.write("fracture_id x y z\n") + for i in range(num_pts): + fwell.write(f"{int(pts[i,0])} {pts[i,1]} {pts[i,2]} {pts[i,3]}\n") + print("--> Cross Checking Complete") + + +def get_segments(well_line_file): + """ Parses well_line_file (avs) to get point information, element information, and list of fractures that intersect the well. + + Parameters + ----------- + well_line_file : string + filename of well_line_file written by find_segments() + + Returns + -------- + pts : list + list of dictionaries of intersection points. dictionary contains fracture id and x,y,z coordinates + elems: list of dictionaries + Information about elements of the discretized well that intersect the DFN + fracture_list : list + list of fractures that the well intersects + + Notes + -------- + None + """ + + with open(well_line_file, "r") as fp: + header = fp.readline().split() + num_pts = int(header[0]) + num_elem = int(header[1]) + pts = [] + for i in range(num_pts): + pt = fp.readline().split() + tmp = {"id": None, "x": None, "y": None, "z": None} + tmp["id"] = int(pt[0]) + tmp["x"] = float(pt[1]) + tmp["y"] = float(pt[2]) + tmp["z"] = float(pt[3]) + pts.append(tmp) + elems = [] + for i in range(num_elem): + elem = fp.readline().split() + tmp = {"pt1": None, "pt2": None, "frac": None} + tmp["pt1"] = int(elem[3]) + tmp["pt2"] = int(elem[4]) + tmp["frac"] = int(elem[1]) + elems.append(tmp) + # get fracture list + fracture_list = [] + for i in range(num_elem): + if not elems[i]["frac"] in fracture_list: + fracture_list.append(elems[i]["frac"]) + + return pts, elems, fracture_list + + +# def get_normal(self, fracture_id): +# """ Returns Normal vector of a fracture + +# Parameters +# ----------- +# fracture_id : int +# fracture number + +# Returns +# -------- +# normal : numpy array +# normal vector of a fracture + +# Notes +# -------- +# None +# """ + +# normals = self.normal_vectors #np.genfromtxt("normal_vectors.dat") +# return normals[fracture_id - 1, :] + + +# def get_center(fracture_id): +# """ Returns center of a fracture + +# Parameters +# ----------- +# fracture_id : int +# fracture number + +# Returns +# -------- +# points : numpy array +# x,y,z coordinates of a fracture + +# Notes +# -------- +# None +# """ +# with open('translations.dat') as old, open('points.dat', 'w') as new: +# old.readline() +# for line in old: +# if not 'R' in line: +# new.write(line) +# points = np.genfromtxt('points.dat', skip_header=0, delimiter=' ') +# return points[fracture_id - 1, :] + + +def rotation_matrix(normalA, normalB): + """ Create a Rotation matrix to transform normal vector A to normal vector B + + Parameters + ----------- + normalA : numpy array + normal vector + normalB : numpy array + normal vector + + + Returns + -------- + R : numpy array + Rotation matrix + + Notes + -------- + None + """ + # Check if normals are the same. + comparison = normalA == normalB + equal_arrays = comparison.all() + + # If they are equal, Return the Identity Matrix + if equal_arrays: + R = np.zeros(9) + R[0] = 1 + R[1] = 0 + R[2] = 0 + R[3] = 0 + R[4] = 1 + R[5] = 0 + R[6] = 0 + R[7] = 0 + R[8] = 1 + # If they are not equal, construct and return a Rotation Matrix + else: + + xProd = np.cross(normalA, normalB) + sin = np.sqrt(xProd[0] * xProd[0] + xProd[1] * xProd[1] + + xProd[2] * xProd[2]) + cos = np.dot(normalA, normalB) + v = np.zeros(9) + v = [ + 0, -xProd[2], xProd[1], xProd[2], 0, -xProd[0], -xProd[1], + xProd[0], 0 + ] + scalar = (1.0 - cos) / (sin * sin) + vSquared = np.zeros(9) + vSquared[0] = (v[0] * v[0] + v[1] * v[3] + v[2] * v[6]) * scalar + vSquared[1] = (v[0] * v[1] + v[1] * v[4] + v[2] * v[7]) * scalar + vSquared[2] = (v[0] * v[2] + v[1] * v[5] + v[2] * v[8]) * scalar + vSquared[3] = (v[3] * v[0] + v[4] * v[3] + v[5] * v[6]) * scalar + vSquared[4] = (v[3] * v[1] + v[4] * v[4] + v[5] * v[7]) * scalar + vSquared[5] = (v[3] * v[2] + v[4] * v[5] + v[5] * v[8]) * scalar + vSquared[6] = (v[6] * v[0] + v[7] * v[3] + v[8] * v[6]) * scalar + vSquared[7] = (v[6] * v[1] + v[7] * v[4] + v[8] * v[7]) * scalar + vSquared[8] = (v[6] * v[2] + v[7] * v[5] + v[8] * v[8]) * scalar + R = np.zeros(9) + R[0] = 1 + v[0] + vSquared[0] + R[1] = 0 + v[1] + vSquared[1] + R[2] = 0 + v[2] + vSquared[2] + R[3] = 0 + v[3] + vSquared[3] + R[4] = 1 + v[4] + vSquared[4] + R[5] = 0 + v[5] + vSquared[5] + R[6] = 0 + v[6] + vSquared[6] + R[7] = 0 + v[7] + vSquared[7] + R[8] = 1 + v[8] + vSquared[8] + + return R + + +def rotate_point(p, R): + """ Apply Rotation matrix R to the point p + + Parameters + ----------- + p : numpy array + point in 3D space + R : numpy array + Rotation matrix + Returns + -------- + v : numpy array + The point p with the rotation matrix applied + + Notes + -------- + None + """ + v = np.zeros(3) + v[0] = p[0] * R[0] + p[1] * R[1] + p[2] * R[2] + v[1] = p[0] * R[3] + p[1] * R[4] + p[2] * R[5] + v[2] = p[0] * R[6] + p[1] * R[7] + p[2] * R[8] + return v + + +
+[docs] +def cleanup_wells(self, wells): + """ Moves working files created while making wells into well_data directory + + Parameters + ----------- + self : object + DFN Class + well: + dictionary of information about the well. Contains the following: + + well["name"] : string + name of the well + + well["filename"] : string + filename of the well coordinates. "well_coords.dat" for example. + Format is : + x0 y0 z0 + x1 y1 z1 + ... + xn yn zn + + well["r"] : float + radius of the well + + Returns + -------- + None + + Notes + -------- + Wells can be a list of well dictionaries + """ + print("--> Cleaning up well files: Starting") + + if not os.path.isdir("well_data"): + os.mkdir("well_data") + + files = ["well_{0}_line.inp", "expand_well_{0}.lgi", \ + "well_{0}_volume.inp","expand_well_{0}.out",\ + "get_well_{0}_zone.lgi", "create_well_{0}.out",\ + "well_{0}_intersect.inp","create_well_{0}.dump",\ + "create_well_{0}.log"] + + if type(wells) is dict: + well = wells + for file in files: + try: + shutil.move(file.format(well['name']), + "well_data/" + file.format(well['name'])) + except: + print("Error moving " + file.format(well['name'])) + pass + + + if type(wells) is list: + for well in wells: + for file in files: + try: + shutil.move(file.format(well['name']), + "well_data/" + file.format(well['name'])) + except: + print("Error moving " + file.format(well['name'])) + pass + print("--> Cleaning up well files: Complete")
+ + +
+[docs] +def combine_well_boundary_zones(self, wells): + """ Processes zone files for particle tracking. All zone files are combined into allboundaries.zone + + Parameters + ---------- + None + + Returns + ------- + None + + Notes + ----- + None + """ + # If there is only 1 well, make a symbolic link + if type(wells) is dict: + os.symlink(f"well_{well['name']}.zone", "well_nodes.zone") + + if type(wells) is list: + number_of_wells = len(wells) + fall = open("well_nodes.zone", "w") + for index, well in enumerate(wells): + if index == 0: + print(f"Working on well {well['name']}") + fzone = open(f"well_{well['name']}.zone", "r") + lines = fzone.readlines() + lines = lines[:-2] + fall.writelines(lines) + if index > 0 and index < number_of_wells - 1: + print(f"Working on well {well['name']}") + fzone = open(f"well_{well['name']}.zone", "r") + lines = fzone.readlines() + lines = lines[1:-2] + lines[0] = f"{index+1:06d}\t\t{well['name']}\n" + fzone.close() + fall.writelines(lines) + if index == number_of_wells - 1: + print(f"Working on well {well['name']}") + fzone = open(f"well_{well['name']}.zone", "r") + lines = fzone.readlines() + lines = lines[1:] + lines[0] = f"{index+1:06d}\t\t{well['name']}\n" + fzone.close() + fall.writelines(lines) + fall.close()
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGraph/dfn2graph.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGraph/dfn2graph.html new file mode 100644 index 000000000..a3d9419c0 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGraph/dfn2graph.html @@ -0,0 +1,555 @@ + + + + + + pydfnworks.dfnGraph.dfn2graph — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for pydfnworks.dfnGraph.dfn2graph

+import networkx as nx
+import numpy as np
+import json
+import sys
+
+from networkx.readwrite import json_graph
+import matplotlib
+
+matplotlib.use('Agg')
+
+import matplotlib.pylab as plt
+
+from pydfnworks.dfnGraph.intersection_graph import create_intersection_graph
+from pydfnworks.dfnGraph.fracture_graph import create_fracture_graph
+from pydfnworks.dfnGraph.bipartite_graph import create_bipartite_graph
+
+
+
+[docs] +def create_graph(self, graph_type, inflow, outflow): + """ Header function to create a graph based on a DFN. Particular algorithms are in files. + + Parameters + ---------- + self : object + DFN Class object + graph_type : string + Option for what graph representation of the DFN is requested. Currently supported are fracture, intersection, and bipartitie + inflow : string + Name of inflow boundary (connect to source) + outflow : string + Name of outflow boundary (connect to target) + + Returns + ------- + G : NetworkX Graph + Graph based on DFN + + Notes + ----- + +""" + ## write hydraulic properties to file. + self.dump_hydraulic_values() + + if graph_type == "fracture": + G = create_fracture_graph(inflow, outflow) + elif graph_type == "intersection": + G = create_intersection_graph(inflow, outflow) + elif graph_type == "bipartite": + G = create_bipartite_graph(inflow, outflow) + else: + print( + f"Error. Unknown graph type.\nType provided: {graph_type}.\nAccetable names: fracture, intersection, bipartite.\nReturning empty graph." + ) + return nx.Graph() + return G
+ + + +def boundary_index(bc_name): + """Determines boundary index in intersections_list.dat from name + + Parameters + ---------- + bc_name : string + Boundary condition name + + Returns + ------- + bc_index : int + integer indexing of cube faces + + Notes + ----- + top = 1 + bottom = 2 + left = 3 + front = 4 + right = 5 + back = 6 + """ + bc_dict = { + "top": -1, + "bottom": -2, + "left": -3, + "front": -4, + "right": -5, + "back": -6 + } + try: + return bc_dict[bc_name] + except: + error = f"Error. Unknown boundary condition: {bc_name} \nExiting\n" + sys.stderr.write(error) + sys.exit(1) + + +
+[docs] +def add_fracture_source(self, G, source): + """ + + Parameters + ---------- + G : NetworkX Graph + NetworkX Graph based on a DFN + source_list : list + list of integers corresponding to fracture numbers + remove_old_source: bool + remove old source from the graph + + Returns + ------- + G : NetworkX Graph + + Notes + ----- + bipartite graph not supported + + """ + + if not type(source) == list: + source = [source] + + print("--> Adding new source connections") + print("--> Warning old source will be removed!!!") + + if G.graph['representation'] == "fracture": + # removing old source term and all connections + G.remove_node('s') + # add new source node + G.add_node('s') + + G.nodes['s']['perm'] = 1.0 + G.nodes['s']['iperm'] = 1.0 + + for u in source: + G.add_edge(u, 's') + + elif G.graph['representation'] == "intersection": + # removing old source term and all connections + nodes_to_remove = ['s'] + for u, d in G.nodes(data=True): + if u != 's' and u != 't': + f1, f2 = d["frac"] + #print("node {0}: f1 {1}, f2 {2}".format(u,f1,f2)) + if f2 == 's': + nodes_to_remove.append(u) + + print("--> Removing nodes: ", nodes_to_remove) + G.remove_nodes_from(nodes_to_remove) + + # add new source node + G.add_node('s') + for u, d in G.nodes(data=True): + if u != 's' and u != 't': + f1 = d["frac"][0] + f2 = d["frac"][1] + if f1 in source: + print( + "--> Adding edge between {0} and new source / fracture {1}" + .format(u, f1)) + G.add_edge(u, 's', frac=f1, length=0., perm=1., iperm=1.) + elif f2 in source: + print( + "--> Adding edge between {0} and new source / fracture {1}" + .format(u, f2)) + G.add_edge(u, 's', frac=f2, length=0., perm=1., iperm=1.) + + elif G.graph['representation'] == "bipartite": + print("--> Not supported for bipartite graph") + print("--> Returning unchanged graph") + return G
+ + + +
+[docs] +def add_fracture_target(self, G, target): + """ + + Parameters + ---------- + G : NetworkX Graph + NetworkX Graph based on a DFN + target : list + list of integers corresponding to fracture numbers + Returns + ------- + G : NetworkX Graph + + Notes + ----- + bipartite graph not supported + + """ + + if not type(target) == list: + source = [target] + + print("--> Adding new target connections") + print("--> Warning old target will be removed!!!") + + if G.graph['representation'] == "fracture": + # removing old target term and all connections + G.remove_node('t') + # add new target node + G.add_node('t') + + G.nodes['t']['perm'] = 1.0 + G.nodes['t']['iperm'] = 1.0 + + for u in target: + G.add_edge(u, 't') + + elif G.graph['representation'] == "intersection": + # removing old target term and all connections + nodes_to_remove = ['t'] + for u, d in G.nodes(data=True): + if u != 's' and u != 't': + f1, f2 = d["frac"] + #print("node {0}: f1 {1}, f2 {2}".format(u,f1,f2)) + if f2 == 't': + nodes_to_remove.append(u) + + print("--> Removing nodes: ", nodes_to_remove) + G.remove_nodes_from(nodes_to_remove) + + # add new target node + G.add_node('t') + for u, d in G.nodes(data=True): + if u != 's' and u != 't': + f1 = d["frac"][0] + f2 = d["frac"][1] + if f1 in target: + print( + "--> Adding edge between {0} and new target / fracture {1}" + .format(u, f1)) + G.add_edge(u, 't', frac=f1, length=0., perm=1., iperm=1.) + elif f2 in target: + print( + "--> Adding edge between {0} and new target / fracture {1}" + .format(u, f2)) + G.add_edge(u, 't', frac=f2, length=0., perm=1., iperm=1.) + + elif G.graph['representation'] == "bipartite": + print("--> Not supported for bipartite graph") + print("--> Returning unchanged graph") + return G
+ + + +def pull_source_and_target(nodes, source='s', target='t'): + """Removes source and target from list of nodes, useful for dumping subnetworks to file for remeshing + + Parameters + ---------- + nodes :list + List of nodes in the graph + source : node + Starting node + target : node + Ending node + Returns + ------- + nodes : list + List of nodes with source and target nodes removed + + Notes + ----- + +""" + for node in [source, target]: + try: + nodes.remove(node) + except: + pass + return nodes + + +
+[docs] +def dump_fractures(self, G, filename): + """Write fracture numbers assocaited with the graph G out into an ASCII file inputs + + Parameters + ---------- + self : object + DFN Class + G : NetworkX graph + NetworkX Graph based on the DFN + filename : string + Output filename + + Returns + ------- + + Notes + ----- + """ + + if G.graph['representation'] == "fracture": + nodes = list(G.nodes()) + elif G.graph['representation'] == "intersection": + nodes = [] + for u, v, d in G.edges(data=True): + nodes.append(G[u][v]['frac']) + nodes = list(set(nodes)) + elif G.graph['representation'] == "bipartite": + nodes = [] + for u, v, d in G.edges(data=True): + nodes.append(G[u][v]['frac']) + nodes = list(set(nodes)) + + nodes = pull_source_and_target(nodes) + fractures = [int(i) for i in nodes] + fractures = sorted(fractures) + print("--> Dumping %s" % filename) + np.savetxt(filename, fractures, fmt="%d")
+ + + +
+[docs] +def plot_graph(self, G, source='s', target='t', output_name="dfn_graph"): + """ Create a png of a graph with source nodes colored blue, target red, and all over nodes black + + Parameters + ---------- + G : NetworkX graph + NetworkX Graph based on the DFN + source : node + Starting node + target : node + Ending node + output_name : string + Name of output file (no .png) + + Returns + ------- + + Notes + ----- + Image is written to output_name.png + + """ + print("\n--> Plotting Graph") + print("--> Output file: %s.png" % output_name) + # get positions for all nodes + pos = nx.spring_layout(G) + nodes = list(G.nodes) + # draw nodes + nx.draw_networkx_nodes(G, + pos, + nodelist=nodes, + node_color='k', + node_size=10, + alpha=1.0) + nx.draw_networkx_nodes(G, + pos, + nodelist=[source], + node_color='b', + node_size=50, + alpha=1.0) + nx.draw_networkx_nodes(G, + pos, + nodelist=[target], + node_color='r', + node_size=50, + alpha=1.0) + + nx.draw_networkx_edges(G, pos, width=1.0, alpha=0.5) + plt.axis('off') + plt.tight_layout() + plt.savefig(output_name + ".png") + plt.clf() + print("--> Plotting Graph Complete\n")
+ + + +
+[docs] +def dump_json_graph(self, G, name): + """Write graph out in json format + + Parameters + ---------- + self : object + DFN Class + G :networkX graph + NetworkX Graph based on the DFN + name : string + Name of output file (no .json) + + Returns + ------- + + Notes + ----- + +""" + print("--> Dumping Graph into file: " + name + ".json") + jsondata = json_graph.node_link_data(G) + with open(name + '.json', 'w') as fp: + json.dump(jsondata, fp) + print("--> Complete")
+ + + +
+[docs] +def load_json_graph(self, name): + """ Read in graph from json format + + Parameters + ---------- + self : object + DFN Class + name : string + Name of input file (no .json) + + Returns + ------- + G :networkX graph + NetworkX Graph based on the DFN +""" + + print(f"Loading Graph in file: {name}.json") + fp = open(name + '.json') + G = json_graph.node_link_graph(json.load(fp)) + print("Complete") + return G
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGraph/graph_flow.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGraph/graph_flow.html new file mode 100644 index 000000000..4db88722d --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGraph/graph_flow.html @@ -0,0 +1,517 @@ + + + + + + pydfnworks.dfnGraph.graph_flow — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for pydfnworks.dfnGraph.graph_flow

+import networkx as nx
+import numpy as np
+import sys
+import scipy.sparse
+import h5py
+
+# pydfnworks modules
+from pydfnworks.dfnGraph.intersection_graph import create_intersection_graph
+from pydfnworks.dfnGraph.graph_attributes import add_perm, add_area, add_weight
+
+
+def get_laplacian_sparse_mat(G,
+                             nodelist=None,
+                             weight=None,
+                             dtype=None,
+                             format='lil'):
+    """ Get the matrices D, A that make up the Laplacian sparse matrix in desired sparsity format. Used to enforce boundary conditions by modifying rows of L = D - A
+
+    Parameters
+    ----------
+        G : object
+            NetworkX graph equipped with weight attribute
+
+        nodelist : list
+            list of nodes of G for which laplacian is desired. Default is None in which case, all the nodes
+        
+        weight : string
+            For weighted Laplacian, else all weights assumed unity
+        
+        dtype :  default is None, cooresponds to float
+        
+        format: string
+            sparse matrix format, csr, csc, coo, lil_matrix with default being lil
+
+    Returns
+    -------
+        D : sparse 2d float array       
+            Diagonal part of Laplacian
+            
+        A : sparse 2d float array
+            Adjacency matrix of graph
+    """
+
+    A = nx.to_scipy_sparse_array(G,
+                                  nodelist=nodelist,
+                                  weight=weight,
+                                  dtype=dtype,
+                                  format=format)
+
+    (n, n) = A.shape
+    data = np.asarray(A.sum(axis=1).T)
+    D = scipy.sparse.spdiags(data, 0, n, n, format=format)
+    return D, A
+
+
+def prepare_graph_with_attributes(inflow, outflow, G=None):
+    """ Create a NetworkX graph, prepare it for flow solve by equipping edges with  attributes, renumber vertices, and tag vertices which are on inlet or outlet
+    
+    Parameters
+    ----------
+        inflow : string
+            name of file containing list of DFN fractures on inflow boundary
+
+        outflow: string
+            name of file containing list of DFN fractures on outflow boundary
+
+    Returns
+    -------
+        Gtilde : NetworkX graph
+    """
+
+    if G == None:
+        G = create_intersection_graph(inflow, outflow)
+
+        Gtilde = G.copy()
+        # need to add aperture
+        add_perm(Gtilde)
+        add_area(Gtilde)
+        add_weight(Gtilde)
+
+    else:
+        Gtilde = G
+        #add_perm(Gtilde)
+        #add_area(Gtilde)
+        add_weight(Gtilde)
+
+    for v in nx.nodes(Gtilde):
+        Gtilde.nodes[v]['inletflag'] = False
+        Gtilde.nodes[v]['outletflag'] = False
+
+    if len(list(nx.neighbors(Gtilde, 's'))) == 0:
+        error = "Error. There are no nodes in the inlet.\nExiting"
+        sys.stderr.write(error)
+        sys.exit(1)
+
+    for v in nx.neighbors(Gtilde, 's'):
+        Gtilde.nodes[v]['inletflag'] = True
+
+    if len(list(nx.neighbors(Gtilde, 't'))) == 0:
+        error = "Error. There are no nodes in the outlet.\nExiting"
+        sys.stderr.write(error)
+        sys.exit(1)
+
+    for v in nx.neighbors(Gtilde, 't'):
+        Gtilde.nodes[v]['outletflag'] = True
+
+    Gtilde.remove_node('s')
+    Gtilde.remove_node('t')
+
+    Gtilde = nx.convert_node_labels_to_integers(Gtilde,
+                                                first_label=0,
+                                                ordering="sorted",
+                                                label_attribute="old_label")
+
+    return Gtilde
+
+
+def solve_flow_on_graph(G, pressure_in, pressure_out, fluid_viscosity, phi):
+    """ Given a NetworkX graph prepared  for flow solve, solve for vertex pressures, and equip edges with attributes (Darcy) flux  and time of travel
+
+    Parameters
+    ----------
+        G : NetworkX graph
+
+        pressure_in : double
+            Value of pressure (in Pa) at inlet
+        
+        pressure_out : double
+            Value of pressure (in Pa) at outlet
+        
+        fluid_viscosity : double
+            optional, in Pa-s, default is for water
+
+        phi : double
+            Porosity, default is 1
+
+    Returns
+    -------
+        H : Acyclic Directed NetworkX graph 
+            H is updated with vertex pressures, edge fluxes and travel times. The only edges that exists are those with postive flow rates. 
+
+    Notes
+    ----------
+        None
+
+    """
+
+    print("--> Starting Graph flow")
+
+    Inlet = [v for v in nx.nodes(G) if G.nodes[v]['inletflag']]
+    Outlet = [v for v in nx.nodes(G) if G.nodes[v]['outletflag']]
+
+    if not set(Inlet).isdisjoint(set(Outlet)):
+        error = "Incompatible graph: Vertex connected to both source and target\n"
+        sys.stderr.write(error)
+        sys.exit(1)
+
+    D, A = get_laplacian_sparse_mat(G, weight='weight', format='lil')
+
+    b = np.zeros(G.number_of_nodes())
+
+    for v in Inlet:
+        b[v] = pressure_in
+        A[v, :] = 0
+        D[v, v] = 1.0
+    for v in Outlet:
+        b[v] = pressure_out
+        A[v, :] = 0
+        D[v, v] = 1.0
+    L = D - A  # automatically converts to csr when returning L
+
+    print("--> Solving Linear System for pressure at nodes")
+    pressure = scipy.sparse.linalg.spsolve(L, b)
+    print("--> Updating graph edges with flow solution")
+
+    for v in nx.nodes(G):
+        G.nodes[v]['pressure'] = pressure[v]
+
+    H = nx.DiGraph()
+    H.add_nodes_from(G.nodes(data=True))
+
+    for u, v in nx.edges(G):
+        # Find direction of flow
+        if G.nodes[u]['pressure'] > G.nodes[v]['pressure']:
+            upstream = u
+            downstream = v
+        elif G.nodes[v]['pressure'] >= G.nodes[u]['pressure']:
+            upstream = v
+            downstream = u
+
+        delta_p = G.nodes[upstream]['pressure'] - G.nodes[downstream][
+            'pressure']
+        if delta_p > 1e-16:
+            ## Create new edge in DiGraph
+            H.add_edge(upstream, downstream)
+            # Transfer edge attributes
+            for att in [
+                    'perm', 'iperm', 'length', 'weight', 'area', 'frac', 'b'
+            ]:
+                H.edges[upstream, downstream][att] = G.edges[upstream,
+                                                             downstream][att]
+
+            H.edges[upstream, downstream]['flux'] = (
+                H.edges[upstream, downstream]['perm'] / fluid_viscosity) * (
+                    delta_p / H.edges[upstream, downstream]['length'])
+
+            H.edges[upstream, downstream]['vol_flow_rate'] = H.edges[
+                upstream, downstream]['flux'] * H.edges[upstream,
+                                                        downstream]['area']
+
+            # H.edges[downstream, upstream]['vol_flow_rate'] =  -1*H.edges[upstream, downstream]['vol_flow_rate']
+
+            H.edges[upstream,
+                    downstream]['velocity'] = H.edges[upstream,
+                                                      downstream]['flux'] / phi
+            H.edges[upstream,
+                    downstream]['time'] = H.edges[upstream, downstream][
+                        'length'] / (H.edges[upstream, downstream]['velocity'])
+
+    print("--> Graph flow complete")
+    return H
+
+
+def compute_dQ(self, G):
+    """ Computes the DFN fracture intensity (p32) and flow channeling density indicator from the graph flow solution on G
+
+    Parameters
+    -----------------
+        self : object
+            DFN Class
+
+        G : networkX graph 
+            Output of run_graph_flow
+
+    Returns
+    ---------------
+        p32 : float
+            Fracture intensity
+        dQ : float flow channeling density indicator 
+
+    Notes
+    ------------
+        For definitions of p32 and dQ along with a discussion see " Hyman, Jeffrey D. "Flow channeling in fracture networks: characterizing the effect of density on preferential flow path formation." Water Resources Research 56.9 (2020): e2020WR027986. "
+
+    """
+    print(
+        "--> Computing fracture intensity (p32) and flow channeling density indicator (dQ)"
+    )
+
+    fracture_surface_area = 2*self.surface_area
+    domain_volume = self.domain['x'] * self.domain['y'] * self.domain['z']
+
+    Qf = np.zeros(self.num_frac)
+    ## convert to undirected
+    H = G.to_undirected()
+    ## walk through fractures
+    for curr_frac in range(1, self.num_frac + 1):
+        # print(f"\nstarting on fracture {curr_frac}")
+        # Gather nodes on current fracture
+        current_nodes = []
+        for u, d in H.nodes(data=True):
+            for f in d["frac"]:
+                if f == curr_frac:
+                    current_nodes.append(u)
+        # cycle through nodes on the fracture and get the outgoing / incoming
+        # volumetric flow rates
+        for u in current_nodes:
+            neighbors = H.neighbors(u)
+            for v in neighbors:
+                if v not in current_nodes:
+                    # outgoing vol flow rate
+                    Qf[curr_frac - 1] += abs(H[u][v]['vol_flow_rate'])
+                    for f in H.nodes[v]['frac']:
+                        if f != curr_frac and f != 's' and f != 't':
+                            # incoming vol flow rate
+                            Qf[f - 1] += abs(H[u][v]['vol_flow_rate'])
+    # Divide by 1/2 to remove up double counting
+    Qf *= 0.5
+    p32 = fracture_surface_area.sum() / domain_volume
+    top = sum(fracture_surface_area * Qf)**2
+    bottom = sum(fracture_surface_area * Qf**2)
+    print(top, bottom)
+    dQ = (1.0 / domain_volume) * (top / bottom)
+    print(f"--> P32: {p32:0.2e} [1/m]")
+    print(f"--> dQ: {dQ:0.2e} [1/m]")
+    print(f"--> Active surface percentage {100*dQ/p32:0.2f}")
+    print(f"--> Geometric equivalent fracture spacing {1/p32:0.2e} m")
+    print(f"--> Hydrological equivalent fracture spacing {1/dQ:0.2e} m")
+    print("--> Complete \n")
+    return p32, dQ, Qf
+
+
+def dump_graph_flow_values(G,graph_flow_filename):
+    """
+    Writes graph flow information to an h5 file named graph_flow_name.
+
+    Parameters
+    --------------------
+        G : NetworkX graph
+            graph with flow variables attached
+
+        graph_flow_filename : string
+            name of output file
+
+    Returns
+    ---------------
+        None
+
+    Notes
+    ---------------
+        name of graph_flow_filename is set in run_graph_flow for primary workflow. Default is graph_flow.hdf5 
+    
+    """
+
+    num_edges = G.number_of_edges()
+    velocity = np.zeros(num_edges)
+    lengths = np.zeros_like(velocity)
+    vol_flow_rate = np.zeros_like(velocity)
+    area = np.zeros_like(velocity)
+    aperture = np.zeros_like(velocity)
+    volume = np.zeros_like(velocity)
+
+    for i, val in enumerate(G.edges(data=True)):
+        u, v, d = val
+        velocity[i] = d['velocity']
+        lengths[i] = d['length']
+        vol_flow_rate[i] = d['vol_flow_rate']
+        area[i] = d['area']
+        aperture[i] = d['b']
+        volume[i] = area[i] * aperture[i]
+
+    print(f"--> Writting flow solution to filename: {graph_flow_filename}")
+    with h5py.File(graph_flow_filename, "w") as f5file:
+        h5dset = f5file.create_dataset('velocity', data=velocity)
+        h5dset = f5file.create_dataset('length', data=lengths)
+        h5dset = f5file.create_dataset('vol_flow_rate', data=vol_flow_rate)
+        h5dset = f5file.create_dataset('area', data=area)
+        h5dset = f5file.create_dataset('aperture', data=aperture)
+        h5dset = f5file.create_dataset('volume', data=volume)
+    f5file.close()
+
+
+
+[docs] +def run_graph_flow(self, + inflow, + outflow, + pressure_in, + pressure_out, + fluid_viscosity=8.9e-4, + phi=1, + G=None, + graph_flow_name = "graph_flow.hdf5"): + """ Solve for pressure driven steady state flow on a graph representation of the DFN. + + Parameters + ---------- + self : object + DFN Class + + inflow : string + name of file containing list of DFN fractures on inflow boundary + + outflow: string + name of file containing list of DFN fractures on outflow boundary + + pressure_in : double + Value of pressure at inlet [Pa] + + pressure_out : double + Value of pressure at outlet [Pa] + + fluid_viscosity : double + optional, default is for water. [Pa*s] + + phi : double + Fracture porosity, default is 1 [-] + + G : Input Graph + + Returns + ------- + Gtilde : NetworkX graph + Gtilde is a directed acyclic graph with vertex pressures, fluxes, velocities, volumetric flow rates, and travel times + + """ + if G == None: + G = self.create_graph("intersection", inflow, outflow) + + Gtilde = prepare_graph_with_attributes(inflow, outflow, G) + Gtilde = solve_flow_on_graph(Gtilde, pressure_in, pressure_out, + fluid_viscosity, phi) + + dump_graph_flow_values(Gtilde, graph_flow_name) + return Gtilde
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGraph/graph_transport.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGraph/graph_transport.html new file mode 100644 index 000000000..187f62104 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGraph/graph_transport.html @@ -0,0 +1,579 @@ + + + + + + pydfnworks.dfnGraph.graph_transport — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for pydfnworks.dfnGraph.graph_transport

+"""
+.. module:: graph_transport.py
+   :synopsis: simulate transport on a pipe network representaiton of a DFN 
+.. moduleauthor:: Shriram Srinivasan <shrirams@lanl.gov>, Jeffrey Hyman <jhyman@lanl.gov>
+
+"""
+
+import timeit
+import sys
+import networkx as nx
+import numpy as np
+import multiprocessing as mp
+
+# pydfnworks graph modules modules
+import pydfnworks.dfnGraph.particle_io as io
+from pydfnworks.dfnGraph.graph_tdrw import set_up_limited_matrix_diffusion
+from pydfnworks.dfnGraph.particle_class import Particle
+
+
+def track_particle(data, verbose=False):
+    """ Tracks a single particle through the graph
+
+        all input parameters are in the dictionary named data 
+
+        Parameters
+        ----------
+            data : dict
+                Dictionary of parameters the includes particle_number, initial_position, 
+                tdrw_flag, matrix_porosity, matrix_diffusivity, cp_flag, control_planes,
+                 direction, G, and nbrs_dict.  
+
+        Returns
+        -------
+            particle : object
+                Particle will full trajectory
+
+    """
+    if verbose:
+        p = mp.current_process()
+        _, cpu_id = p.name.split("-")
+        cpu_id = int(cpu_id)
+        print(
+            f"--> Particle {data['particle_number']} is starting on worker {cpu_id}"
+        )
+
+    particle = Particle(data["particle_number"], data["initial_position"],
+                        data["tdrw_flag"], data["matrix_porosity"],
+                        data["matrix_diffusivity"], data["fracture_spacing"],
+                        data["trans_prob"], data["transfer_time"],
+                        data["cp_flag"], data["control_planes"],
+                        data["direction"])
+
+    # # get current process information
+    global nbrs_dict
+    global G_global
+    particle.track(G_global, nbrs_dict)
+    if verbose:
+        print(
+            f"--> Particle {data['particle_number']} is complete on worker {cpu_id}"
+        )
+    return particle
+
+
+def get_initial_posititions(G, initial_positions, nparticles):
+    """ Distributes initial particle positions 
+
+        Parameters
+        ----------
+                
+            G : NetworkX graph 
+                obtained from graph_flow
+
+        initial_positions : str
+            distribution of initial conditions. options are uniform and flux (flux-weighted)
+
+        nparticles : int
+            requested number of particles
+
+        Returns
+        -------
+            ip : numpy array
+                array nparticles long. Each element is the initial position for each particle
+
+        """
+
+    inlet_nodes = [v for v in nx.nodes(G) if G.nodes[v]['inletflag']]
+    cnt = len(inlet_nodes)
+    print(f"--> There are {cnt} inlet nodes")
+    if cnt == 0:
+        error = "Error. There are no nodes in the inlet.\nExiting"
+        sys.stderr.write(error)
+        sys.exit(1)
+
+    # Uniform Distribution for particles
+    if initial_positions == "uniform":
+        print("--> Using uniform initial positions.")
+        ip = np.zeros(nparticles).astype(int)
+        n = int(np.ceil(nparticles / cnt))
+        print(f"--> {n} particles will be placed at every inflow node.\n")
+        ## this could be cleaned up using clever indexing
+        inflow_idx = 0
+        inflow_cnt = 0
+        for i in range(nparticles):
+            ip[i] = inlet_nodes[inflow_idx]
+            inflow_cnt += 1
+            if inflow_cnt >= n:
+                inflow_idx += 1
+                inflow_cnt = 0
+
+    ## flux weighted initial positions for particles
+    elif initial_positions == "flux":
+        print("--> Using flux-weighted initial positions.\n")
+        flux = np.zeros(cnt)
+        for i, u in enumerate(inlet_nodes):
+            for v in G.successors(u):
+                flux[i] += G.edges[u, v]['flux']
+        flux /= flux.sum()
+        flux_cnts = [np.ceil(nparticles * i) for i in flux]
+        nparticles = int(sum(flux_cnts))
+        ip = np.zeros(nparticles).astype(int)
+        ## Populate ip with Flux Cnts
+        ## this could be cleaned up using clever indexing
+        inflow_idx = 0
+        inflow_cnt = 0
+        for i in range(nparticles):
+            ip[i] = inlet_nodes[inflow_idx]
+            inflow_cnt += 1
+            if inflow_cnt >= flux_cnts[inflow_idx]:
+                inflow_idx += 1
+                inflow_cnt = 0
+
+    # Throw error if unknown initial position is provided
+    else:
+        error = f"Error. Unknown initial_positions input {initial_positions}. Options are uniform or flux \n"
+        sys.stderr.write(error)
+        sys.exit(1)
+
+    return ip, nparticles
+
+
+def create_neighbor_list(G):
+    """ Create a list of downstream neighbor vertices for every vertex on NetworkX graph obtained after running graph_flow
+
+    Parameters
+    ----------
+        G: NetworkX graph 
+            Directed Graph obtained from output of graph_flow
+
+    Returns
+    -------
+        dict : nested dictionary.
+
+    Notes
+    -----
+        dict[n]['child'] is a list of vertices downstream to vertex n
+        dict[n]['prob'] is a list of probabilities for choosing a downstream node for vertex n
+    """
+
+    nbrs_dict = {}
+
+    for u in nx.nodes(G):
+
+        if G.nodes[u]['outletflag']:
+            continue
+
+        node_list = []
+        prob_list = []
+        nbrs_dict[u] = {}
+
+        for v in G.successors(u):
+            node_list.append(v)
+            prob_list.append(G.edges[u, v]['vol_flow_rate'])
+
+        if node_list:
+            nbrs_dict[u]['child'] = node_list
+            nbrs_dict[u]['prob'] = np.asarray(prob_list) / sum(prob_list)
+        else:
+            nbrs_dict[u]['child'] = None
+            nbrs_dict[u]['prob'] = None
+
+    return nbrs_dict
+
+
+def check_tdrw_params(matrix_porosity, matrix_diffusivity, fracture_spacing):
+    """ Check that the provided tdrw values are physiscal
+
+
+    Parameters
+    ----------
+        G: NetworkX graph 
+            Directed Graph obtained from output of graph_flow
+
+    Returns
+    -------
+        dict : nested dictionary.
+
+    Notes
+    -----
+        dict[n]['child'] is a list of vertices downstream to vertex n
+        dict[n]['prob'] is a list of probabilities for choosing a downstream node for vertex n
+    
+    """
+
+    if matrix_porosity is None:
+        error = f"Error. Requested TDRW but no value for matrix_porosity was provided\n"
+        sys.stderr.write(error)
+        sys.exit(1)
+    elif matrix_porosity < 0 or matrix_porosity > 1:
+        error = f"Error. Requested TDRW but value for matrix_porosity provided is outside of [0,1]. Value provided {matrix_porosity}\n"
+        sys.stderr.write(error)
+        sys.exit(1)
+    if matrix_diffusivity is None:
+        error = f"Error. Requested TDRW but no value for matrix_diffusivity was provided\n"
+        sys.stderr.write(error)
+        sys.exit(1)
+
+    if fracture_spacing is not None:
+        if fracture_spacing <= 0:
+            error = f"Error. Non-positive value for fracture_spacing was provided.\nValue {fracture_spacing}\nExiting program"
+            sys.stderr.write(error)
+            sys.exit(1)
+
+
+def check_control_planes(control_planes, direction):
+    control_plane_flag = False
+    if not type(control_planes) is list:
+        error = f"Error. provided controls planes are not a list\n"
+        sys.stderr.write(error)
+        sys.exit(1)
+    else:
+        # add None to indicate the end of the control plane list
+        control_plane_flag = True
+
+    if direction is None:
+        error = f"Error. Primary direction not provided. Required for control planes\n"
+        sys.stderr.write(error)
+        sys.exit(1)
+    elif direction not in ['x', 'y', 'z']:
+        error = f"Error. Primary direction is not known. Acceptable values are x,y, and z\n"
+        sys.stderr.write(error)
+        sys.exit(1)
+
+    print(f"--> Control Planes: {control_planes}")
+    print(f"--> Direction: {direction}")
+    return control_plane_flag
+
+
+
+[docs] +def run_graph_transport(self, + G, + nparticles, + partime_file, + frac_id_file=None, + format='hdf5', + initial_positions="uniform", + dump_traj=False, + tdrw_flag=False, + matrix_porosity=None, + matrix_diffusivity=None, + fracture_spacing=None, + control_planes=None, + direction=None, + cp_filename='control_planes'): + """ Run particle tracking on the given NetworkX graph + + Parameters + ---------- + self : object + DFN Class + + G : NetworkX graph + obtained from graph_flow + + nparticles: int + number of particles + + initial_positions : str + distribution of initial conditions. options are uniform and flux (flux-weighted) + + partime_file : string + name of file to which the total travel times and lengths will be written for each particle + + frac_id_file : string + name of file to which detailed information of each particle's travel will be written + + dump_flag: bool + on/off to write full trajectory information to file + + tdrw_flag : Bool + if False, matrix_porosity and matrix_diffusivity are ignored + + matrix_porosity: float + Matrix Porosity used in TDRW + + matrix_diffusivity: float + Matrix Diffusivity used in TDRW (SI units m^2/s) + + fracture_spaceing : float + finite block size for limited matrix diffusion + + control_planes : list of floats + list of control plane locations to dump travel times. Only in primary direction of flow. + + primary direction : string (x,y,z) + string indicating primary direction of flow + + Returns + ------- + particles : list + list of particles objects + + Notes + ----- + Information on individual functions is found therein + """ + ## the flow graph needs to be a global variable so all processors can access it + ## without making a copy of it. + global G_global + G_global = nx.Graph() + G_global = G.copy() + + if not format in ['ascii', 'hdf5']: + error = ( + f"--> Error. Unknown file format provided in run_graph_transport.\n\n--> Provided value is {format}.\n--> Options: 'ascii' or 'hdf5'.\n\nExitting\n\n" + ) + sys.stderr.write(error) + sys.exit(1) + + print("\n--> Running Graph Particle Tracking") + # Check parameters for TDRW + if tdrw_flag: + check_tdrw_params(matrix_porosity, matrix_diffusivity, + fracture_spacing) + print( + f"--> Running particle transport with TDRW.\n--> Matrix porosity {matrix_porosity}.\n--> Matrix Diffusivity {matrix_diffusivity} m^2/s" + ) + + if control_planes is None: + control_plane_flag = False + else: + control_plane_flag = check_control_planes( + control_planes=control_planes, direction=direction) + print(f"--> Control Plane Flag {control_plane_flag}") + + print("--> Creating downstream neighbor list") + global nbrs_dict + nbrs_dict = create_neighbor_list(G) + + print("--> Getting initial Conditions") + ip, nparticles = get_initial_posititions(G, initial_positions, nparticles) + + print(f"--> Starting particle tracking for {nparticles} particles") + + if dump_traj: + print(f"--> Writing trajectory information to file") + + if fracture_spacing is not None: + print(f"--> Using limited matrix block size for TDRW") + print(f"--> Fracture spacing {fracture_spacing:0.2e} [m]") + trans_prob = set_up_limited_matrix_diffusion(G, fracture_spacing, + matrix_porosity, + matrix_diffusivity) + # This doesn't change for the system. + # Transfer time diffusing between fracture blocks + transfer_time = fracture_spacing**2 / (2 * matrix_diffusivity) + else: + trans_prob = None + transfer_time = None + ## main loop + if self.ncpu == 1: + tic = timeit.default_timer() + particles = [] + for i in range(nparticles): + if i % 1000 == 0: + print(f"--> Starting particle {i} out of {nparticles}") + particle = Particle(i, ip[i], tdrw_flag, matrix_porosity, + matrix_diffusivity, fracture_spacing, + trans_prob, transfer_time, control_plane_flag, + control_planes, direction) + particle.track(G, nbrs_dict) + particles.append(particle) + + elapsed = timeit.default_timer() - tic + print( + f"--> Main Tracking Loop Complete. Time Required {elapsed:0.2e} seconds" + ) + stuck_particles = io.dump_particle_info(particles, partime_file, + frac_id_file, format) + if control_plane_flag: + io.dump_control_planes(particles, control_planes, cp_filename, + format) + + if dump_traj: + io.dump_trajectories(particles, 1) + + if self.ncpu > 1: + print(f"--> Using {self.ncpu} processors") + ## Prepare input data + inputs = [] + + tic = timeit.default_timer() + pool = mp.Pool(min(self.ncpu, nparticles)) + + particles = [] + + def gather_output(output): + particles.append(output) + + for i in range(nparticles): + data = {} + data["particle_number"] = i + data["initial_position"] = ip[i] + data["tdrw_flag"] = tdrw_flag + data["matrix_porosity"] = matrix_porosity + data["matrix_diffusivity"] = matrix_diffusivity + data["fracture_spacing"] = fracture_spacing + data["transfer_time"] = transfer_time + data["trans_prob"] = trans_prob + data["cp_flag"] = control_plane_flag + data["control_planes"] = control_planes + data["direction"] = direction + pool.apply_async(track_particle, + args=(data, ), + callback=gather_output) + + pool.close() + pool.join() + pool.terminate() + + elapsed = timeit.default_timer() - tic + print( + f"--> Main Tracking Loop Complete. Time Required {elapsed:0.2e} seconds" + ) + + stuck_particles = io.dump_particle_info(particles, partime_file, + frac_id_file, format) + if control_plane_flag: + io.dump_control_planes(particles, control_planes, cp_filename, + format) + + if dump_traj: + io.dump_trajectories(particles, min(self.ncpu, nparticles)) + + if stuck_particles == 0: + print("--> All particles exited the network") + print("--> Graph Particle Tracking Completed Successfully.") + else: + print( + f"--> Out of {nparticles} particles, {stuck_particles} particles did not exit" + ) + + # Clean up and delete the global versions + del G_global + del nbrs_dict + + return particles
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGraph/pruning.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGraph/pruning.html new file mode 100644 index 000000000..57a90598a --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnGraph/pruning.html @@ -0,0 +1,318 @@ + + + + + + pydfnworks.dfnGraph.pruning — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for pydfnworks.dfnGraph.pruning

+import numpy as np
+import networkx as nx
+
+from networkx.algorithms.flow.shortestaugmentingpath import *
+from networkx.algorithms.flow.edmondskarp import *
+from networkx.algorithms.flow.preflowpush import *
+
+from itertools import islice
+
+
+def current_flow_threshold(self,
+                           G,
+                           source="s",
+                           target="t",
+                           weight=None,
+                           thrs=0.0):
+    """ Runs current flow (Potential drop between source and target) on the Graph G, and returns a subgraph such that the current on the edges is greater than the threshold value (thrs).
+    
+    Parameters
+    ----------
+        G : NetworkX Graph
+            NetworkX Graph based on a DFN 
+        source : node 
+            Starting node
+        target : node
+            Ending node
+        weight : string
+            Resistance term used in the solution of Laplace's Equation
+        thrs: float
+            Threshold value for pruning the graph
+
+    Returns 
+    -------
+        H : NetworkX graph
+            Subgraph such that the current on the edges is greater than the threshold value
+
+    Notes
+    -----
+        Graph attributes (node and edge) are not retained on the subgraph H. 
+    """
+
+    print(
+        f'--> Running Current Flow with weight : {weight} and threshold {thrs}'
+    )
+    cf = nx.edge_current_flow_betweenness_centrality_subset(G,
+                                                            sources=[source],
+                                                            targets=[target],
+                                                            weight=weight)
+    print("Current Flow Complete")
+    currentflow_edges = [(u, v) for (u, v), d in cf.items() if d > thrs]
+    H = G.edge_subgraph(currentflow_edges).copy()   
+    H.graph["representation"] = G.graph["representation"]
+    # H = nx.Graph(currentflow_edges, representation=G.graph["representation"])
+    print(
+        f"--> Of the {G.number_of_nodes()} in the original graph,  {H.number_of_nodes()} are in the thresholded network"
+    )
+    print("--> Running Current Flow Complete")
+    return H
+
+
+def k_shortest_paths(G, k, source, target, weight):
+    """Returns the k shortest paths in a graph 
+    
+    Parameters
+    ----------
+        G : NetworkX Graph
+            NetworkX Graph based on a DFN 
+        k : int
+            Number of requested paths
+        source : node 
+            Starting node
+        target : node
+            Ending node
+        weight : string
+            Edge weight used for finding the shortest path
+
+    Returns 
+    -------
+        paths : sets of nodes
+            a list of lists of nodes in the k shortest paths
+
+    Notes
+    -----
+    Edge weights must be numerical and non-negative
+"""
+    return list(
+        islice(nx.shortest_simple_paths(G, source, target, weight=weight), k))
+
+
+
+[docs] +def k_shortest_paths_backbone(self, G, k, source='s', target='t', weight=None): + """Returns the subgraph made up of the k shortest paths in a graph + + Parameters + ---------- + G : NetworkX Graph + NetworkX Graph based on a DFN + k : int + Number of requested paths + source : node + Starting node + target : node + Ending node + weight : string + Edge weight used for finding the shortest path + + Returns + ------- + H : NetworkX Graph + Subgraph of G made up of the k shortest paths + + Notes + ----- + See Hyman et al. 2017 "Predictions of first passage times in sparse discrete fracture networks using graph-based reductions" Physical Review E for more details +""" + + print(f"\n--> Determining {k} shortest paths in the network") + H = G.copy() + k_shortest = set([]) + for path in k_shortest_paths(G, k, source, target, weight): + k_shortest |= set(path) + k_shortest.remove('s') + k_shortest.remove('t') + path_nodes = sorted(list(k_shortest)) + path_nodes.append('s') + path_nodes.append('t') + nodes = list(G.nodes()) + secondary = list(set(nodes) - set(path_nodes)) + for n in secondary: + H.remove_node(n) + return H + print("--> Complete\n")
+ + + +
+[docs] +def greedy_edge_disjoint(self, G, source='s', target='t', weight='None', k=''): + """ + Greedy Algorithm to find edge disjoint subgraph from s to t. + See Hyman et al. 2018 SIAM MMS + + Parameters + ---------- + self : object + DFN Class Object + G : NetworkX graph + NetworkX Graph based on the DFN + source : node + Starting node + target : node + Ending node + weight : string + Edge weight used for finding the shortest path + k : int + Number of edge disjoint paths requested + + Returns + ------- + H : NetworkX Graph + Subgraph of G made up of the k shortest of all edge-disjoint paths from source to target + + Notes + ----- + 1. Edge weights must be numerical and non-negative. + 2. See Hyman et al. 2018 "Identifying Backbones in Three-Dimensional Discrete Fracture Networks: A Bipartite Graph-Based Approach" SIAM Multiscale Modeling and Simulation for more details + + """ + print("--> Identifying edge disjoint paths") + if G.graph['representation'] != "intersection": + print( + "--> ERROR!!! Wrong type of DFN graph representation\nRepresentation must be intersection\nReturning Empty Graph\n" + ) + return nx.Graph() + Gprime = G.copy() + Hprime = nx.Graph() + Hprime.graph['representation'] = G.graph['representation'] + cnt = 0 + + # if a number of paths in not provided k will equal the min cut between s and t + min_cut = len(nx.minimum_edge_cut(G, 's', 't')) + if k == '' or k > min_cut: + k = min_cut + + while nx.has_path(Gprime, source, target): + path = nx.shortest_path(Gprime, source, target, weight=weight) + H = Gprime.subgraph(path) + Hprime.add_edges_from(H.edges(data=True)) + Gprime.remove_edges_from(list(H.edges())) + + cnt += 1 + if cnt > k: + break + print("--> Complete") + return Hprime
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnTrans/transport.html b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnTrans/transport.html new file mode 100644 index 000000000..8deddcf24 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_modules/pydfnworks/dfnTrans/transport.html @@ -0,0 +1,487 @@ + + + + + + pydfnworks.dfnTrans.transport — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for pydfnworks.dfnTrans.transport

+import os
+import sys
+import shutil
+from time import time
+import subprocess
+
+
+
+[docs] +def dfn_trans(self): + """Primary driver for dfnTrans. + + Parameters + --------- + self : object + DFN Class + + Returns + -------- + None + """ + print('=' * 80) + print("\ndfnTrans Starting\n") + print('=' * 80) + tic = time() + self.copy_dfn_trans_files() + self.check_dfn_trans_run_files() + self.run_dfn_trans() + delta_time = time() - tic + self.dump_time('Process: dfnTrans', delta_time) + print('=' * 80) + print("\ndfnTrans Complete\n") + print("Time Required for dfnTrans: %0.2f Seconds\n" % delta_time) + print('=' * 80)
+ + + +
+[docs] +def copy_dfn_trans_files(self): + """Creates symlink to dfnTrans Execuateble and copies input files for dfnTrans into working directory + + Parameters + --------- + self : object + DFN Class + + Returns + -------- + None + """ + + print("Attempting to Copy %s\n" % self.dfnTrans_file) + try: + shutil.copy(self.dfnTrans_file, os.path.abspath(os.getcwd())) + except OSError: + print("--> Problem copying %s file" % self.local_dfnTrans_file) + print("--> Trying to delete and recopy") + os.remove(self.local_dfnTrans_file) + shutil.copy(self.dfnTrans_file, os.path.abspath(os.getcwd())) + except: + print("--> ERROR: Problem copying %s file\n" % self.dfnTrans_file) + error = "Unable to replace. Exiting Program\n" + sys.stderr.write(error) + sys.exit(1)
+ + + +
+[docs] +def run_dfn_trans(self): + """ Execute dfnTrans + + Parameters + --------- + self : object + DFN Class + + Returns + -------- + None + """ + tic = time() + failure = subprocess.call(os.environ['DFNTRANS_EXE'] + ' ' + + self.local_dfnTrans_file, + shell=True) + self.dump_time("Function: DFNTrans ", time() - tic) + if failure != 0: + error = "--> ERROR: dfnTrans did not complete\n" + sys.stderr.write(error) + sys.exit(1)
+ + + + + + + +
+[docs] +def check_dfn_trans_run_files(self): + """ Ensures that all files required for dfnTrans run are in the current directory + + Parameters + --------- + self : object + DFN Class + + Returns + -------- + None + + Notes + ------- + None + """ + cwd = os.getcwd() + print( + "\nChecking that all files required for dfnTrans are in the current directory" + ) + print("--> Current Working Directory: %s" % cwd) + print("--> dfnTrans is running from: %s" % self.local_dfnTrans_file) + + print("--> Checking DFNTrans Parameters") + params = { + "param:": None, + "poly:": None, + "inp:": None, + "stor:": None, + "boundary:": None, + "out_grid:": None, + "out_3dflow:": None, + "out_init:": None, + "out_tort:": None, + "out_curv:": None, + "out_avs:": None, + "out_traj:": None, + "out_fract:": None, + "out_filetemp:": None, + "out_dir:": None, + "out_path:": None, + "out_time:": None, + "ControlPlane:": None, + "control_out:": None, + "delta_Control:": None, + "flowdir:": None, + "init_nf:": None, + "init_partn:": None, + "init_eqd:": None, + "init_npart:": None, + "init_fluxw:": None, + "init_totalnumber:": None, + "init_oneregion:": None, + "in_partn:": None, + "init_well:": None, + "init_nodepart:": None, + "in_xmin:": None, + "in_xmax:": None, + "in_ymin:": None, + "in_ymax:": None, + "in_zmin:": None, + "in_zmax:": None, + "init_random:": None, + "in_randpart:": None, + "init_matrix:": None, + "inm_coord:": None, + "inm_nodeID:": None, + "inm_porosity:": None, + "inm_diffcoeff:": None, + "streamline_routing:": None, + "tdrw:": None, + "tdrw_porosity:": None, + "tdrw_diffcoeff:": None, + "timesteps:": None, + "time_units:": None, + "flux_weight:": None, + "seed:": None, + "in-flow-boundary:": None, + "out-flow-boundary:": None, + "aperture:": None, + "aperture_type:": None, + "aperture_file:": None, + "porosity": None, + "density:": None, + "satur:": None, + "thickness:": None + } + + files = ["param:", "poly:", "inp:", "stor:", "boundary:"] + + if self.flow_solver == "PFLOTRAN": + params["PFLOTRAN_vel:"] = None + files.append("PFLOTRAN_vel:") + + params["PFLOTRAN_cell:"] = None + files.append("PFLOTRAN_cell:") + + params["PFLOTRAN_uge:"] = None + files.append("PFLOTRAN_uge:") + + if self.flow_solver == "FEHM": + params["FEHM_fin:"] = None + files.append("FEHM_fin:") + + # Parse DFNTrans input and fill dictionary + keys = params.keys() + with open(self.local_dfnTrans_file) as fp: + + for line in fp.readlines(): + if "/*" in line: + comment = line + line = line[:line.index( + "/*")] ## only process text before '/*' comment + if "//" in line: + line = line[:line.index("//")] + + if len(line) > 0: + for key in keys: + if key in line: + if params[key] == None: + params[key] = line.split()[1] + + #for p in params.keys(): + # print(p,params[p]) + + # Check if file required for the run are in the directory and are not empty + for key in files: + if params[key] is None: + error = f"ERROR!!!!!\nRequired file {key} was not provided.\nPlease check DFNTrans control file\nExiting Program\n" + sys.stderr.write(error) + sys.exit(1) + elif not os.path.isfile(params[key]): + error = "ERROR!!!!!\nRequired file %s is not in the current directory.\nPlease check required files\nExiting Program\n" % params[ + key] + sys.stderr.write(error) + sys.exit(1) + + print( + "--> All files required for dfnTrans have been found in current directory\n\n" + ) + + for required in [ + "out_grid:", "out_3dflow:", "out_init:", "out_tort:", "out_curv:", + "out_avs:", "out_traj:", "out_fract:", "out_filetemp:", "out_dir:", + "out_path:", "out_time:", "timesteps:", "time_units:", + "flux_weight:", "seed:", "in-flow-boundary:", "out-flow-boundary:", + "aperture:", "porosity", "density:", "satur:", + "streamline_routing:" + ]: + if params[required] == None: + error = "ERROR!!!\n%s not provided. Exiting\n\n" % (required) + sys.stderr.write(error) + sys.exit(1) + + # Check Initial conditions, make sure only 1 Initial condition is selected and that + # required parameters have been defined + print("--> Checking Initial Conditions") + initial_conditions = [ + ("init_nf:", "init_partn:"), ("init_eqd:", "init_npart:"), + ("init_fluxw:", "init_totalnumber:"), ("init_random:", "in_randpart:"), + ("init_oneregion:", "in_partn:", "in_xmin:", "in_ymin:", "in_zmin:", + "in_xmax:", "in_ymax:", "in_zmax:"), + ("init_matrix:", "inm_coord:", "inm_nodeID:", "inm_porosity:"), + ("init_well:", "init_nodepart:") + ] + ic_selected = [] + for ic in initial_conditions: + #print(ic,params[ic[0]]) + if params[ic[0]] == "yes": + ic_selected.append(ic[0]) + for i in ic: + if params[i] == None: + error = "Initial condition %s selected but %s not provided\n" % ( + ic[0], i) + sys.stderr.write(error) + sys.exit(1) + if len(ic_selected) > 1: + error = "ERROR!!! More than one initial condition defined\nExiting\n" + sys.stderr.write(error) + print("Selected Initial Conditions:\n:") + for ic in ic_selected: + print(ic) + print() + sys.exit(1) + elif len(ic_selected) == 0: + error = "ERROR!!! No initial condition defined\nExiting\n" + sys.stderr.write(error) + sys.exit(1) + + if params["ControlPlane:"] != None: + for required in ["control_out:", "delta_Control:", "flowdir:"]: + if params[required] == None: + error = "Parameter %s required for ControlPlane\n" % required + sys.stderr.write(error) + sys.exit(1) + + if params["tdrw:"] == "yes": + if params["time_units:"] != "seconds": + error = "ERROR!!!You must use seconds for the time_units to run TDRW" + sys.stderr.write(error) + sys.exit(1) + + for required in ["tdrw_porosity:", "tdrw_diffcoeff:"]: + if params[required] == None: + error = "Parameter %s required for tdrw\n" % required + sys.stderr.write(error) + sys.exit(1) + + if params["aperture:"] == "yes": + if params["aperture_type:"] == None: + error = "Parameter aperture_type: required for aperture: yes\n" + sys.stderr.write(error) + sys.exit(1) + + else: + if not os.path.isfile(params["aperture_file:"]) or os.stat( + params["aperture_file:"]).st_size == 0: + error = "aperture_file: %s not found or empty\n" % params[ + "aperture_file:"] + sys.stderr.write(error) + sys.exit(1) + + else: + if params["thickness:"] == None: + error = "Parameter thickness: required for aperture: no:\n" + sys.stderr.write(error) + sys.exit(1) + + print("--> Checking Initial Conditions Complete")
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_sources/applications.rst.txt b/Documentation/sphinx-docs/build/html/_sources/applications.rst.txt new file mode 100644 index 000000000..62b7d7bef --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_sources/applications.rst.txt @@ -0,0 +1,53 @@ +.. j_applications-chapter: + +Example Applications +==================== + +Carbon dioxide sequestration +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +dfnWorks provides the framework necessary to perform multiphase simulations (such as flow and reactive transport) at the reservoir scale. A particular application, highlighted here, is sequestering |CO2| from anthropogenic sources and disposing it in geological formations such as deep saline aquifers and abandoned oil fields. Geological |CO2| sequestration is one of the principal methods under consideration to reduce carbon footprint in the atmosphere due to fossil fuels (Bachu, 2002; Pacala and Socolow, 2004). For safe and sustainable long-term storage of |CO2| and to prevent leaks through existing faults and fractured rock (along with the ones created during the injection process), understanding the complex physical and chemical interactions between |CO2| , water (or brine) and fractured rock, is vital. dfnWorks capability to study multiphase flow in a DFN can be used to study potential |CO2| migration through cap-rock, a potential risk associated with proposed subsurface storage of |CO2| in saline aquifers or depleted reservoirs. Moreover, using the reactive transport capabilities of PFLOTRAN coupled with cell-based transmissivity of the DFN allows one to study dynamically changing permeability fields with mineral precipitation and dissolution due to |CO2| –water interaction with rock. + +.. figure:: ./figures/time_co2.png + :scale: 50 % + :alt: alternate text + :align: center + + *Temporal evolution of supercritical |CO2| displacing water in a meter cube DFN containing 24 fractures. The DFN is initially fully saturated with water, (top left time 0 hours) and supercritical |CO2| is slowly injected into the system from the bottom of the domain to displace the water for a total time of 10 h. There is an initial flush through the system during the first hour of the simulation, and then the rate of displacement decreases.* + +Shale energy extraction +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Hydraulic fracturing (fracking) has provided access to hydrocarbon trapped in low-permeability media, such as tight shales. The process involves injecting water at high pressures to reactivate existing fractures and also create new fractures to increase permeability of the shale allowing hydrocarbons to be extracted. However, the fundamental physics of why fracking works and its long term ramifications are not well understood. Karra et al. (2015) used dfnWorks to generate a typical production site and simulate production. Using this physics based model, they found good agreement with production field data and determined what physical mechanisms control the decline in the production curve. + +.. figure:: ./figures/well-pressure.png + :scale: 10 % + :alt: alternate text + :align: center + + *Pressure in a well used for hydraulic fracturing.* + +Nuclear waste repository +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The Swedish Nuclear Fuel and Waste Management Company (SKB) has undertaken a detailed investigation of the fractured granite at the Forsmark, Sweden site as a potential host formation for a subsurface repository for spent nuclear fuel (SKB, 2011; Hartley and Joyce, 2013). The Forsmark area is about 120 km north of Stockholm in northern Uppland, and the repository is proposed +to be constructed in crystalline bedrock at a depth of approximately 500 m. Based on the SKB site investigation, a statistical fracture model with multiple fracture sets was developed; detailed parameters of the Forsmark site model are in SKB (2011). We adopt a subset of the model that consist of three sets of background (non-deterministic) circular fractures whose orientations follow a Fisher distribution, fracture radii are sampled from a truncated power-law distribution, the transmissivity of the fractures is estimated using a power-law model based on the fracture radius, and the fracture aperture is related to the fracture size using the cubic law (Adler et al., 2012). Under such a formulation, the fracture apertures are uniform on each fracture, but vary among fractures. The network is generated in a cubic domain with sides of length one-kilometer. Dirichlet boundary conditions are imposed on the top (1 MPa) and bottom (2 MPa) of the domain to create a pressure gradient aligned with the vertical axis, and noflow boundary conditions are enforced along lateral boundaries. + + +.. figure:: ./figures/forsmark_trajectories.png + :scale: 10 % + :alt: alternate text + :align: center + + *Simulated particle trajectories in fractured granite at Forsmark, Sweden.* + +Sources: + +- Adler, P.M., Thovert, J.-F., Mourzenko, V.V., 2012. Fractured Porous Media. Oxford University Press, Oxford, United Kingdom. +- Bachu, S., 2002. Sequestration of |CO2| in geological media in response to climate change: road map for site selection using the transform of the geological space into the |CO2| phase space. Energy Convers. Manag. 43, 87–102. +- Hartley, L., Joyce, S., 2013. Approaches and algorithms for groundwater flow modeling in support of site investigations and safety assessment of the Fors- mark site, Sweden. J. Hydrol. 500, 200–216. +- Karra, S., Makedonska, N., Viswanathan, H., Painter, S., Hyman, J., 2015. Effect of advective flow in fractures and matrix diffusion on natural gas production. Water Resour. Res., under review. +- Pacala, S., Socolow, R., 2004. Stabilization wedges: solving the climate problem for the next 50 years with current technologies. Science 305, 968–972. +- SKB, Long-Term Safety for the Final Repository for Spent Nuclear Fuel at Forsmark. Main Report of the SR-Site Project. Technical Report SKB TR-11-01, Swedish Nuclear Fuel and Waste Management Co., Stockholm, Sweden, 2011. + +.. |CO2| replace:: CO\ :sub:`2` diff --git a/Documentation/sphinx-docs/build/html/_sources/dfnflow.rst.txt b/Documentation/sphinx-docs/build/html/_sources/dfnflow.rst.txt new file mode 100644 index 000000000..082bf27ab --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_sources/dfnflow.rst.txt @@ -0,0 +1,156 @@ +.. _dfnflow-chapter: + +dfnFlow +======== +*dfnFlow* involves using flow solver such as PFLOTRAN or FEHM. PFLOTRAN is recommended if a large number of fractures ( > O(1000)) are involved in a network. Using the function calls that are part of pydfnworks, one can create the mesh files needed to run PFLOTRAN. This will involve creating unstructured mesh file ``*uge`` as well as the boundary ``*ex`` files. Please see the PFLOTRAN user manual at http://www.pflotran.org under unstructured *explicit* format usage for further details. An example input file for PFLOTRAN is provided in the repository. Please use this as a starting point to build your input deck. + +Below is a sample input file. Refer to the PFLOTRAN user manual at http://www.pflotran.org for input parameter descriptions. + +.. code-block:: c + + # Jan 13, 2014 + # Nataliia Makedonska, Satish Karra, LANL + #================================================ + + SIMULATION + SIMULATION_TYPE SUBSURFACE + PROCESS_MODELS + SUBSURFACE_FLOW flow + MODE RICHARDS + / + / + END + SUBSURFACE + + DFN + + #=========================== discretization =================================== + GRID + TYPE unstructured_explicit full_mesh_vol_area.uge + GRAVITY 0.d0 0.d0 0.d0 + END + + + #=========================== fluid properties ================================= + FLUID_PROPERTY + DIFFUSION_COEFFICIENT 1.d-9 + END + + DATASET Permeability + FILENAME dfn_properties.h5 + END + + #=========================== material properties ============================== + MATERIAL_PROPERTY soil1 + ID 1 + POROSITY 0.25d0 + TORTUOSITY 0.5d0 + CHARACTERISTIC_CURVES default + PERMEABILITY + DATASET Permeability + / + END + + + #=========================== characteristic curves ============================ + CHARACTERISTIC_CURVES default + SATURATION_FUNCTION VAN_GENUCHTEN + M 0.5d0 + ALPHA 1.d-4 + LIQUID_RESIDUAL_SATURATION 0.1d0 + MAX_CAPILLARY_PRESSURE 1.d8 + / + PERMEABILITY_FUNCTION MUALEM_VG_LIQ + M 0.5d0 + LIQUID_RESIDUAL_SATURATION 0.1d0 + / + END + + #=========================== output options =================================== + OUTPUT + TIMES s 0.01 0.05 0.1 0.2 0.5 1 + # FORMAT TECPLOT BLOCK + PRINT_PRIMAL_GRID + FORMAT VTK + MASS_FLOWRATE + MASS_BALANCE + VARIABLES + LIQUID_PRESSURE + PERMEABILITY + / + END + + #=========================== times ============================================ + TIME + INITIAL_TIMESTEP_SIZE 1.d-8 s + FINAL_TIME 1.d0 d== + MAXIMUM_TIMESTEP_SIZE 10.d0 d + STEADY_STATE + END + + # REFERENCE_PRESSURE 1500000. + + #=========================== regions ========================================== + REGION All + COORDINATES + -1.d20 -1.d20 -1.d20 + 1.d20 1.d20 1.d20 + / + END + + REGION inflow + FILE pboundary_left_w.ex + END + + REGION outflow + FILE pboundary_right_e.ex + END + + #=========================== flow conditions ================================== + FLOW_CONDITION initial + TYPE + PRESSURE dirichlet + / + PRESSURE 1.01325d6 + END + + + FLOW_CONDITION outflow + TYPE + PRESSURE dirichlet + / + PRESSURE 1.d6 + END + + FLOW_CONDITION inflow + TYPE + PRESSURE dirichlet + / + PRESSURE 2.d6 + END + + #=========================== condition couplers =============================== + # initial condition + INITIAL_CONDITION + FLOW_CONDITION initial + REGION All + END + + + BOUNDARY_CONDITION INFLOW + FLOW_CONDITION inflow + REGION inflow + END + + BOUNDARY_CONDITION OUTFLOW + FLOW_CONDITION outflow + REGION outflow + END + + #=========================== stratigraphy couplers ============================ + STRATA + REGION All + MATERIAL soil1 + END + + END_SUBSURFACE diff --git a/Documentation/sphinx-docs/build/html/_sources/dfngen.rst.txt b/Documentation/sphinx-docs/build/html/_sources/dfngen.rst.txt new file mode 100644 index 000000000..6eaadaccb --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_sources/dfngen.rst.txt @@ -0,0 +1,27 @@ +.. _dfngen-chapter: + +dfnGen - C++ Generation Code +################################# + +dfnGen creates the discrete fracture networks using the feature rejection algorithm for meshing (FRAM). Fractures can be created stochastically or as deterministic features. + +The detailed description of FRAM and the implemented methodology is in `\J. D. Hyman, C. W. Gable, S. L. Painter, and N. Makedonska. Conforming Delaunay triangulation of stochastically generated three dimensional discrete fracture networks: A feature rejection algorithm for meshing strategy. SIAM J. Sci. Comput., 36(4):A1871–A1894, 2014 `_. + + +.. include:: dfngen_docs/dfngen_domain.inc + +.. include:: dfngen_docs/dfngen_fracture_ellipses.inc + +.. include:: dfngen_docs/dfngen_fracture_rectangles.inc + +.. include:: dfngen_docs/dfngen_user_fractures.inc + +.. + .. include:: dfngen_docs/dfngen_hydro.inc + +Source Code Documentation (Doxygen_) +************************************************** + +.. _Doxygen: dfnGen_docs/index.html + + diff --git a/Documentation/sphinx-docs/build/html/_sources/dfntrans.rst.txt b/Documentation/sphinx-docs/build/html/_sources/dfntrans.rst.txt new file mode 100644 index 000000000..87a66bc89 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_sources/dfntrans.rst.txt @@ -0,0 +1,42 @@ +.. _dftrans-chapter: + +dfnTrans +============ + +dfnTrans is a method for resolving solute transport using control volume flow +solutions obtained from dfnFlow on the unstructured mesh generated using dfnGen. +We adopt a Lagrangian approach and represent a non-reactive conservative solute +as a collection of indivisible passive tracer particles. Particle tracking +methods (a) provide a wealth of information about the local flow field, (b) do +not suffer from numerical dispersion, which is inherent in the discretizations +of advection–dispersion equations, and (c) allow for the computation of each +particle trajectory to be performed in an intrinsically parallel fashion if +particles are not allowed to interact with one another or the fracture network. +However, particle tracking on a DFN poses unique challenges that arise from (a) +the quality of the flow solution, (b) the unstructured mesh representation of +the DFN, and (c) the physical phenomena of interest. The flow solutions obtained +from dfnFlow are locally mass conserving, so the particle tracking method does +not suffer from the problems inherent in using Galerkin finite element codes. + +dfnTrans starts from reconstruction of local velocity field: Darcy fluxes +obtained using dfnFlow are used to reconstruct the local velocity field, which +is used for particle tracking on the DFN. Then, Lagrangian transport simulation +is used to determine pathlines through the network and simulate transport. It is +important to note that dfnTrans itself only solves for advective transport, but +effects of longitudinal dispersion and matrix diffusion, sorption, and other +retention processes are easily incorporated by post-processing particle +trajectories. + +The detailed description of dfnTrans algorithm and implemented +methodology is in `Makedonska, N., Painter, S. L., Bui, Q. M., Gable, C. W., & +Karra, S. (2015). Particle tracking approach for transport in three-dimensional +discrete fracture networks. Computational Geosciences, 19(5), 1123-1137. +`_ + + +Documentation +-------------- +Doxygen_ + +.. _Doxygen: dfnTrans_docs/index.html + diff --git a/Documentation/sphinx-docs/build/html/_sources/examples.rst.txt b/Documentation/sphinx-docs/build/html/_sources/examples.rst.txt new file mode 100644 index 000000000..15065d38a --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_sources/examples.rst.txt @@ -0,0 +1,104 @@ +Examples +============================= + + +This section contains a few examples of DFN generated using dfnWorks. All required input files for these examples are contained in the folder dfnWorks/examples/. The focus of this document is to provide visual confirmation that new users of dfnWorks have the code set up correctly, can carry out the following runs and reproduce the following images. All images are rendered using Paraview, which can be obtained for free at http : //www.paraview.org/. The first two examples are simplest so it is recommended that the user proceed in the order presented here. + +All examples are in the examples/ directory. Within each subdirectory are the files required to run the example. The command line input is found in notes.txt. Be sure that you have created ~/test_output_files prior to running the examples. + + +4_user_defined_rects +-------------------------- + +Location: examples/4_user_defined_rects/ + + +This test case consists of four user defined rectangular fractures within a a cubic domain with sides of length one meter. The network of four fractures, each colored by material ID. The computational mesh is overlaid on the fractures. This image is created by loading the file full_mesh.inp. located in the job folder into Paraview. + +.. figure:: figures/4_user_rectangles.png + :scale: 10 % + :alt: alternate text + :align: center + + *The meshed network of four rectangular fractures.* + +High pressure (red) Dirichlet boundary conditions are applied on the edge of the single fracture along the boundary x = -0.5, and low pressure (blue) boundary conditions are applied on the edges of the two fractures at the boundary x = 0.5. +This image is created by loading the file parsed_vtk/dfn_explicit-001.vtk into Paraview. + + +Particles are inserted uniformly along the inlet fracture on the left side of the image. +Particles exit the domain through the two horizontal fractures on the right side of the image. +Due to the stochastic nature of the particle tracking algorithm, your pathlines might not be exactly the same as in this image. +Trajectories are colored by the current velocity magnitude of the particle's velocity. +Trajectories can be visualized by loading the files part\_*.inp, in the folder 4_user_rectangles/traj/trajectories/ + +We have used the extract surface and tube filters in paraview for visual clarity. + + +4_user_defined_ell_uniform +-------------------------- + +Location: examples/4_user_defined_ell_uniform/ + + +This test case consists of four user defined elliptical fractures within a a cubic domain with sides of length one meter. In this case the ellipses are approximated using 8 vertices. We have set the meshing resolution to be uniform by including the argument slope=0 into the mesh_networks function in run_explicit.py. + +.. figure:: figures/4_user_ellipses.png + :scale: 10 % + :alt: alternate text + :align: center + + *The uniformly meshed network of four circular fractures.* + + + +exp: Exponentially Distributed fracture lengths +----------------------------------------------------- + +Location: examples/exp/ + +This test case consists of a family of fractures whose size is exponentially distributed with a minimum size of 1m and a maximum size of 50m. The domain is cubic with an edge length of 10m. All input parameters for the generator can be found in tests/gen_exponential_dist.dat. We have changed the flow direction to be aligned with the y-axis by modifying the PFLOTRAN input card dfn_explicit.in + +.. figure:: figures/exp_pressure.png + :scale: 10 % + :alt: alternate text + :align: center + + *Pressure solution on with rectangular fractures whose lengths following a exponential distribution. Gradient is aligned with the Y-Axis* + + +TPL: Truncated Power-Law +---------------------------------- + +Location: examples/TPL/ + +This test case consists of two families whose sizes have a truncated power law distribution with a minimum size of 1m and a maximum size of 5m an exponent 2.6. The domain size is cubic with an edge length of 15m. + +.. figure:: figures/power_mesh.png + :scale: 20 % + :alt: alternate text + :align: center + + +Graph-based pruning +---------------------- + +Location: examples/pruning/ + + +This example uses a graph representation of a DFN to isolate the 2-core. The pruned DFN has all dead end fractures of the network are removed. This example has two run_explicit.py scripts. The first creates the original DFN and identifies the 2-core using networkx (https://networkx.github.io/). The second meshes the DFN corresponding to the 2-core of the graph and then runs flow and transport. The 2 core network is in a sub-directory 2-core. The original network has 207 fractures and the 2-core has 79 fractures. + +.. figure:: figures/dfn_2_core.png + :scale: 30 % + :alt: alternate text + :align: center + + *(left) Graph based on DFN topology. Each vertex is a fracture in the network. The inflow boundary is colored blue and the outflow is colored red. (right) 2-Core of the graph to the left.* + +.. figure:: figures/pruned_network.png + :scale: 5 % + :alt: alternate text + :align: center + + *(left) Original DFN (right) DFN corresponding to the 2-core of the DFN to the left.* + diff --git a/Documentation/sphinx-docs/build/html/_sources/gallery.rst.txt b/Documentation/sphinx-docs/build/html/_sources/gallery.rst.txt new file mode 100644 index 000000000..73c5f8bbd --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_sources/gallery.rst.txt @@ -0,0 +1,42 @@ +dfnWorks Gallery +============================= + + +.. figure:: figures/TPL_pathlines.png + :alt: Figure Not Found + :align: center + + *Particle Pathlines within a DFN composed of fractures whose radii follow a truncated powerlaw. Fractures are colored by Pressure.* + +.. figure:: figures/power_mesh.png + :alt: Figure Not Found + :align: center + + *Mesh of a DFN composed of fractures whose radii follow a truncated powerlaw. Fractures are colored by Pressure.* + +.. figure:: figures/well-pressure.png + :alt: Figure Not Found + :align: center + + *Pressure distribution with a hydraulic fracturing simulation* + +.. figure:: figures/dead-end_velocity_field.png + :alt: Figure Not Found + :align: center + + *Pressure contours and velocity vector field within a dead-end fracture.* + +.. figure:: figures/dfn_graph.png + :alt: Figure Not Found + :align: center + + *DFN along with it's graph representation* + +.. figure:: figures/in-fracture-variability_pathlines.png + :alt: Figure Not Found + :align: center + + *DFN with internal aperture variability. Particle Pathlines are shown in purple.* + + + diff --git a/docs/_sources/index.rst.txt b/Documentation/sphinx-docs/build/html/_sources/index_docs.rst.txt similarity index 100% rename from docs/_sources/index.rst.txt rename to Documentation/sphinx-docs/build/html/_sources/index_docs.rst.txt diff --git a/Documentation/sphinx-docs/build/html/_sources/intro.rst.txt b/Documentation/sphinx-docs/build/html/_sources/intro.rst.txt new file mode 100644 index 000000000..72c369583 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_sources/intro.rst.txt @@ -0,0 +1,260 @@ +Welcome To dfnWorks +========================= + +dfnWorks is a parallelized computational suite to generate three-dimensional +discrete fracture networks (DFN) and simulate flow and transport. Developed at +Los Alamos National Laboratory, it has been used to study flow and transport +in fractured media at scales ranging from millimeters to kilometers. The +networks are created and meshed using dfnGen, which combines FRAM (the feature +rejection algorithm for meshing) methodology to stochastically generate +three-dimensional DFNs with the LaGriT meshing toolbox to create a high-quality +computational mesh representation. The representation produces a conforming +Delaunay triangulation suitable for high-performance computing finite volume +solvers in an intrinsically parallel fashion. Flow through the network is +simulated with dfnFlow, which utilizes the massively parallel subsurface flow +and reactive transport finite volume code PFLOTRAN. A Lagrangian approach to +simulating transport through the DFN is adopted within dfnTrans to determine +pathlines and solute transport through the DFN. Applications of the dfnWorks +suite include nuclear waste repository science, hydraulic fracturing and +|CO2| sequestration. + +.. |CO2| replace:: CO\ :sub:`2` + +To run a workflow using the dfnWorks suite, the pydfnworks package is +highly recommended. pydfnworks calls various tools in the dfnWorks suite with +the aim to provide a seamless workflow for scientific applications of dfnWorks. + +Obtaining dfnWorks +--------------------------- +dfnWorks can be downloaded from https://github.com/lanl/dfnWorks/ + +A docker container of dfnWorks can be downloaded from https://hub.docker.com/r/ees16/dfnworks + + +Citing dfnWorks +--------------- +`Hyman, J. D., Karra, S., Makedonska, N., Gable, C. W., Painter, S. L., & +Viswanathan, H. S. (2015). dfnWorks: A discrete fracture network framework +for modeling subsurface flow and transport. Computers & Geosciences, 84, +10-19. `_ + +*BibTex:* + +.. code-block:: none + + @article{hyman2015dfnWorks, + title={dfnWorks: A discrete fracture network framework + for modeling subsurface flow and transport}, + author={Hyman, Jeffrey D and Karra, Satish and Makedonska, + Nataliia and Gable, Carl W and Painter, Scott L + and Viswanathan, Hari S}, + journal={Computers \& Geosciences}, + volume={84}, + pages={10--19}, + year={2015}, + publisher={Elsevier} + } + +Versions +------------------- + +v2.8 - Current +^^^^^^^^^^^^^^^^^^^^^^^^ + +- New Meshing Using Poisson Disc Sampling (Requires LaGriT v3.3) +- Conforming Discrete Fracture Matrix Meshing +- ECPM module using MAP DFN +- Additional bug fixes +- New dfnGraph model capabilities +- TDRW matrix diffusion with finite matrix-block size + +v2.7 +^^^^^^^^^^^^^^^^^^^^^^^^ + +- Python based assignment of domain parameters, fracture families, user defined fractures +- Interactive object interface +- Updated for PFLOTRAN 4.0 compatability +- Additional bug fixes +- Increased detail of warning and errors + + +v2.6 +^^^^^^^^^^^^^^^^^^^^^^^^ + +- Hydraulic aperture of fracture based on background stress field +- Bug fixes + + +v2.5 +^^^^^^^^^^^^^^^^^^^^^^^^ + +- New Generation parameters, family orientation by trend/plunge and dip/strike +- Define fracture families by region +- Updated output report + + +v2.4 +^^^^^^^^^^^^^^^^^^^^^^^^ + +- New meshing technique (Poisson disc sampling) +- Define fracture families by region +- Updated output report +- Well Package + +v2.3 +^^^^^^^^^^^^^^^^^^^^^^^^ + +- Bug fixes in LaGrit Meshing +- Bug fixes in dfnTrans checking +- Bug fixes in dfnTrans output +- Expanded examples +- Added PDF printing abilities + + +v2.2 +^^^^^^^^^^^^^^^^^^^^^^^^ + +- pydfnWorks updated for python3 +- Graph based (pipe-network approximations) for flow and transport +- Bug fixes in LaGrit Meshing +- Increased functionalities in pydfnworks including the path option +- dfn2graph capabilities +- FEHM flow solver +- Streamline routing option in dfnTrans +- Time Domain Random Walk in dfnTrans + +v2.1 +^^^^^^^^^^^^^^^^^^^^^^^^ + +- Bug fixes in LaGrit Meshing +- Increased functionalities in pydfnworks including the path option + +v2.0 +^^^^^^^^^^^^^^^^^^^^^^^^ + +- New dfnGen C++ code which is much faster than the Mathematica dfnGen. This code has successfully generated networks with 350,000+ fractures. +- Increased functionality in the pydfnworks package for more streamlined workflow from dfnGen through visualization. + + +About this manual +------------------ + +This manual comprises of information on setting up inputs to dfnGen, dfnTrans +and PFLOTRAN, as well as details on the pydfnworks module: :ref:`pydfnworks +`. Finally, the manual contains a short tutorial +with prepared examples that can be found in the ``examples`` directory of the +dfnWorks repository, and a description of some applications of the dfnWorks +suite. + +Contact +-------- + +Please email dfnworks@lanl.gov with questions about dfnWorks. Please let us know if you publish using dfnWorks and we'll add it to the :ref:`Publication Page ` + +Contributors +------------- +LANL +^^^^^^^ +- Jeffrey D. Hyman +- Matt Sweeney +- Nataliia Makedonska +- Carl Gable +- Hari Viswanathan +- Aric Hagberg +- Shriram Srinivasan +- Aidan Stansberry + +External +^^^^^^^^^^^^^^ +- Satish Karra (PNNL) +- Scott Painter (ORNL) +- Quan Bui (now at LLNL) +- Jeremy Harrod (now at Spectra Logic) +- Thomas Sherman (University of Notre Dame) +- Johannes Krotz (Oregon State University) +- Yu Chen + + +Copyright Information +---------------------- + +Documentation: + +LA-UR-17-22216 + +Software copyright: + +LA-CC-17-027 + +Contact Information : dfnworks@lanl.gov + +(or copyright) 2018 Triad National Security, LLC. All rights reserved. + +This program was produced under U.S. Government contract 89233218CNA000001 +for Los Alamos National Laboratory (LANL), which is operated by Triad +National Security, LLC for the U.S. Department of Energy/National Nuclear +Security Administration. + +All rights in the program are reserved by Triad National Security, LLC, +and the U.S. Department of Energy/National Nuclear Security Administration. +The Government is granted for itself and others acting on its behalf a +nonexclusive, paid-up, irrevocable worldwide license in this material +to reproduce, prepare derivative works, distribute copies to the public, +perform publicly and display publicly, and to permit others to do so. + + +The U.S. Government has rights to use, reproduce, and distribute this software. +NEITHER THE GOVERNMENT NOR TRIAD NATIONAL SECURITY, LLC MAKES ANY WARRANTY, +EXPRESS OR IMPLIED, OR ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE. +If software is modified to produce derivative works, such modified +software should be clearly marked, so as not to confuse it with the +version available from LANL. + +Additionally, this program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2 of the License, or (at your option) +any later version. Accordingly, this program is distributed in the hope that it +will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +License for more details. + +Additionally, redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following conditions are +met: +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of Los Alamos National Security, LLC, Los Alamos +National Laboratory, LANL, the U.S. Government, nor the names of its +contributors may be used to endorse or promote products derived from this +software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY LOS ALAMOS NATIONAL SECURITY, LLC AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL LOS ALAMOS NATIONAL +SECURITY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +Additionally, this program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. Accordingly, this program is distributed in the +hope that it will be useful, but WITHOUT ANY WARRANTY; without even the +implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +See the GNU General Public License for more details. + + +.. dfnWorks documentation master file, created by Satish Karra Oct 6, 2016 + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + diff --git a/Documentation/sphinx-docs/build/html/_sources/output.rst.txt b/Documentation/sphinx-docs/build/html/_sources/output.rst.txt new file mode 100644 index 000000000..9de1a0669 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_sources/output.rst.txt @@ -0,0 +1,386 @@ +.. _output-chapter: + +Run Files +============= + +This section describes the contents and purpose of each file used in dfnWorks and their locations. + +dfnGen - output +------------------------ + +**connectivity.dat:** + +.. _connectivity.dat: + +Fracture connection list. Each row corresponds to a single fracture. The integers in that row are the fractures that fracture intersects with. These are the non-zero elements of the adjacency matrix. + +**DFN_output.txt:** + +.. _DFN_output.txt: + +Detailed information about fracture network. Output by DFNGen. + +**families.dat:** + +.. _families.dat: + +Information about fracture families. Produced by DFNGen. + +**input_generator.dat:** + +.. _input_generator.dat: + +Input file for DFN generator. + +**input_generator_clean.dat:** + +.. _input_generator_clean.dat: + +Abbreviated input file for DFN generator. + +**normal_vectors.dat:** + +.. _normal_vectors.dat: + +Normal vector of each fracture in the network. + +**params.txt:** + +.. _params.txt: + +Parameter information about the fracture network used for meshing. Includes number of fractures, h, visualmode, expected number of dudded points, and x,y,z dimensions of the domain. + +**poly_info.dat:** + +.. _poly_info.dat: + +Fracture information output by DFNGen. Format: Fracture Number, Family number, rotation angle for rotateln in LaGriT, x0, y0, z0, x1, y1, z1 (end points of line of rotation). + +**user_rects.dat:** + +.. _user_rects.dat: + +User defined rectangle file. + +**radii.dat:** + +.. _radii.dat: + +Concatentate file of fracture radii. Contains fractures that are removed due to isolation. + + +**radii_Final.dat:** + +.. _radii_Final.dat: + +Concatentated file of final radii in the DFN. + + +**rejections.dat:** + +.. _rejections.dat: + +Summary of rejection reasons. + +**rejectsPerAttempt.dat:** + +.. _rejectsPerAttempt.dat: + +Number of rejections per attempted fracture. + + +**translations.dat:** + +.. _translations.dat: + +Fracture centriods. + + +**triple_points.dat:** + +.. _triple_points.dat: + +x,y,z location of triple intersection points. + + +**warningFileDFNGen.txt:** + +.. _warningFileDFNGen.txt: + +Warning file output by DFNGen. + +**intersection_list.dat:** + +.. _intersection_list.dat: + +List of intersections between fractures. Format is fracture1 fracture2 x y z length. Negative numbers correspond to intersections with boundaries. + +LaGrit - Output +------------------ + +**bound_zones.lgi:** + +.. _bound_zones.lgi: + +LaGriT run file to identify boundary nodes. Dumps zone files. + +**boundary_output.txt:** + +.. _boundary_output.txt: + +Output file from bound_zones.lgi. + +**finalmesh.txt:** + +.. _finalmesh.txt: + +Brief summary of final mesh. + +**full_mesh.inp:** + +.. _full_mesh.inp: + +Full DFN mesh in AVS format. + +**full_mesh.lg:** + +.. _full_mesh.lg: + +Full DFN mesh in LaGriT binary format. + +**full_mesh.uge:** + +.. _full_mesh.uge: + +Full DFN mesh in UGE format. NOTE volumes are not correct in this file. This file is processed by convert_uge to create full_mesh_vol_area.uge, which has the correct volumes. + +**full_mesh_viz.inp:** + +.. _full_mesh_viz.inp: + +**intersections:** + +.. _intersections: + +Directory containing intersection avs files output by the generator and used by LaGrit. + +**lagrit_logs:** + +.. _lagrit_logs: + +Directory of output files from individual meshing. + +**logx3dgen:** + +.. _logx3dgen: + +LaGriT output. + +**outx3dgen:** + +.. _outx3dgen: + +LaGriT output. + +**parameters:** + +.. _parameters: + +Directory of parameter*.mgli files used for fracture meshing. + + +**polys:** + +.. _polys: + +Subdirectory contiaining AVS file for polygon boundaries. + +**tri_fracture.stor:** + +.. _tri_fracture.stor: + +FEHM stor file. Information about cell volume and area. + +**user_function.lgi:** + +.. _user_function.lgi: + +Function used by LaGriT for meshing. Defines coarsening gradient. + + +PFLOTRAN - output +-------------------- + +Fracture based aperture value for the DFN. Used to rescale volumes in full_mesh_vol_area.uge. + +**cellinfo.dat:** + +.. _cellinfo.dat: + +Mesh information output by PFLOTRAN. + +**dfn_explicit-000.vtk:** + +.. _dfn_explicit-000.vtk: + +VTK file of initial conditions of PFLOTRAN. Mesh is not included in this file. + +**dfn_explicit-001.vtk:** + +.. _dfn_explicit-001.vtk: + +VTK file of steady-state solution of PFLOTRAN. Mesh is not included in this file. + +**dfn_explicit-mas.dat:** + +.. _dfn_explicit-mas.dat: + +pflotran information file. + +**dfn_explicit.in:** + +.. _dfn_explicit.in: + +pflotran input file. + +**_dfn_explicit.out:** + +.. _dfn_explicit.out: + +pflotran output file. + +**dfn_properties.h5:** + +.. _dfn_properties.h5: + +h5 file of fracture network properties, permeability, used by pflotran. + + +Full DFN mesh with limited attributes in AVS format. + +**full_mesh_vol_area.uge:** + +.. _full_mesh_vol_area.uge: + +Full DFN in uge format. Volumes and areas have been corrected. + +**materialid.dat:** + +.. _materialid.dat: + +Material ID (Fracture Number) for every node in the mesh. + +**parsed_vtk:** + +.. _parsed_vtk: + +Directory of pflotran results. + +**perm.dat:** + +.. _perm.dat: + +Fracture permeabilities in FEHM format. Each fracture is listed as a zone, starting index at 7. + +**pboundary_back_n.ex:** + +.. _pboundary_back_n.ex: + +Boundary file for back of the domain used by PFLOTRAN. + +**pboundary_bottom.ex:** + +.. _pboundary_bottom.ex: + +Boundary file for bottom of the domain used by PFLOTRAN. + +**pboundary_front_s.ex:** + +.. _pboundary_front_s.ex: + +Boundary file for front of the domain used by PFLOTRAN. + +**pboundary_left_w.ex:** + +.. _pboundary_left_w.ex: + +Boundary file for left side of the domain used by PFLOTRAN. + +**pboundary_right_e.ex:** + +.. _pboundary_right_e.ex: + +Boundary file for right of the domain used by PFLOTRAN. + +**pboundary_top.ex:** + +.. _pboundary_top.ex: + +Boundary file for top of the domain used by PFLOTRAN. + +.. dfnTrans +.. ------------- + +.. **allboundaries.zone:** + +.. .. _allboundaries.zone: + +.. Concatenated file of all zone files. + +.. **darcyvel.dat:** + +.. .. _darcyvel.dat: + +.. Concatenated file of darcy velocities output by PFLOTRAN. + +.. **dfnTrans_output_dir:** + +.. .. _dfnTrans_output_dir: + +.. Outpur directory from DFNTrans. Particle travel times, trajectories, and reconstructed Velocities are in this directory. + +.. **PTDFN_control.dat:** + +.. .. _PTDFN_control.dat: + +.. Input file for DFNTrans. + +.. **pboundary_back_n.zone:** + +.. .. _pboundary_back_s.zone: + +.. Boundary zone file for the back of the domain. Normal vector (0,1,0) +- pi/2 + +.. **pboundary_bottom.zone:** + +.. .. _pboundary_bottom.zone: + +.. Boundary zone file for the bottom of the domain. Normal vector (0,0,-1) +- pi/2 + +.. **pboundary_front_s.zone:** + +.. .. _pboundary_front_n.zone: + +.. Boundary zone file for the front of the domain. Normal vector (0,-1,0) +- pi/2 + + +.. **pboundary_left_w.zone:** + +.. .. _pboundary_left_w.zone: + +.. Boundary zone file for the left side of the domain. Normal vector (-1,0,0) +- pi/2 + + +.. **pboundary_right_e.zone:** + +.. .. _pboundary_right_e.zone: + + +.. Boundary zone file for the bottom of the domain. Normal vector (1,0,0) +- pi/2 + +.. **pboundary_top.zone:** + +.. .. _pboundary_top.zone: + +.. Boundary zone file for the top of the domain. Normal vector (0,0,1) +- pi/2 + diff --git a/Documentation/sphinx-docs/build/html/_sources/publications.rst.txt b/Documentation/sphinx-docs/build/html/_sources/publications.rst.txt new file mode 100644 index 000000000..7d8f99dbd --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_sources/publications.rst.txt @@ -0,0 +1,127 @@ +.. _publications-chapter: + +dfnWorks Publications +====================== + +The following are publications that use *dfnWorks*: + +#. `\J. D. Hyman, C. W. Gable, S. L. Painter, and N. Makedonska. Conforming Delaunay triangulation of stochastically generated three dimensional discrete fracture networks: A feature rejection algorithm for meshing strategy. SIAM J. Sci. Comput. (2014) `_. + +#. `\R.S. Middleton, J.W. Carey, R.P. Currier, J. D. Hyman, Q. Kang, S. Karra, J. Jimenez-Martınez, M.L. Porter, and H.S. Viswanathan. Shale gas and non-aqueous fracturing fluids: Opportunities and challenges for supercritical CO2. Applied Energy, (2015) `_. + +#. `\J. D. Hyman, S. L. Painter, H. Viswanathan, N. Makedonska, and S. Karra. Influence of injection mode on transport properties in kilometer-scale three-dimensional discrete fracture networks. Water Resources Research (2015) `_. + +#. `\S. Karra, Nataliia Makedonska, Hari S Viswanathan, Scott L Painter, and Jeffrey D. Hyman. Effect of advective flow in fractures and matrix diffusion on natural gas production. Water Resources Research (2015) `_. + +#. `\J. D. Hyman, S. Karra, N. Makedonska, C. W Gable, S. L Painter, and H. S Viswanathan. dfnWorks: A discrete fracture network framework for modeling subsurface flow and transport. Computers & Geosciences (2015) `_. + +#. `\H. S. Viswanathan, J. D. Hyman, S. Karra, J.W. Carey, M. L. Porter, E. Rougier, R. P. Currier,Q. Kang, L. Zhou, J. Jimenez-Martınez, N. Makedonska, L. Chen, and R. S. Middleton. Using Discovery Science To Increase Efficiency of Hydraulic Fracturing While Reducing Water Usage, chapter 4, pages 71–88. ACS Publications, (2016) `_. + +#. `\N. Makedonska, S. L Painter, Q. M Bui, C. W Gable, and S. Karra. Particle tracking approach for transport in three-dimensional discrete fracture networks. Computational Geosciences (2015) `_. + +#. `\D. O’Malley, S. Karra, R. P. Currier, N. Makedonska, J. D. Hyman, and H. S. Viswanathan. Where does water go during hydraulic fracturing? Groundwater (2016) `_. + +#. `\J. D. Hyman, J Jiménez-Martínez, HS Viswanathan, JW Carey, ML Porter, E Rougier, S Karra, Q Kang, L Frash, L Chen, et al. Understanding hydraulic fracturing: a multi-scale problem. Phil. Trans. R. Soc. A, (2016) `_. + +#. `\G. Aldrich, J. D. Hyman, S. Karra, C. W. Gable, N. Makedonska, H. Viswanathan, J.Woodring, and B. Hamann. Analysis and visualization of discrete fracture networks using a flow topology graph. IEEE Transactions on Visualization and Computer Graphics (2017) `_. + +#. `\N. Makedonska, J. D. Hyman, S. Karra, S. L. Painter, C.W. Gable, and H. S. Viswanathan. Evaluating the effect of internal aperture variability on transport in kilometer scale discrete fracture networks. Advances in Water Resources (2016) `_. + +#. `\J. D. Hyman, G. Aldrich, H. Viswanathan, N. Makedonska, and S. Karra. Fracture size and transmissivity correlations: Implications for transport simulations in sparse three-dimensional discrete fracture networks following a truncated power law distribution of fracture size. Water Resources Research (2016) `_. + +#. `\H. Djidjev, D. O’Malley, H. Viswanathan, J. D. Hyman, S. Karra, and G. Srinivasan. Learning on graphs for predictions of fracture propagation, flow and transport. In 2017 IEEE International Parallel and Distributed Processing Symposium Workshops (IPDPSW) (2017) `_. + +#. `\J. D. Hyman, A. Hagberg, G. Srinivasan, J. Mohd-Yusof, and H. Viswanathan. Predictions of first passage times in sparse discrete fracture networks using graph-based reductions. Phys. Rev. E, 96:013304, Jul `_. + +#. `\T Hadgu, S. Karra, N. Makedonska, J. D. Hyman, K. Klise, H. S. Viswanathan, and Y.Wang. A comparative study of discrete fracture network and equivalent continuum models for simulating flow and transport in the far field of a hypothetical nuclear waste repository in crystalline host rock. J. Hydrology, 2017 `_. + +#. `\V. Romano, J. D. Hyman, S. Karra, A. J. Valocchi, M. Battaglia, and S. Bigi. Numerical modeling of fluid flow in a fault zone: a case of study from majella mountain (Italy). Energy Procedia, 125:556 – 560, 2017 `_. + +#. `\M. Valera, Z. Guo, P. Kelly, S. Matz, A. Cantu, A.G. Percus, J. D. Hyman, G. Srinivasan, and H.S. Viswanathan. Machine learning for graph-based representations of three-dimensional discrete fracture networks. Computational Geosciences, (2018) `_. + +#. `\M. K. Mudunuru, S. Karra, N. Makedonska, and T. Chen. Sequential geophysical and flow inversion to characterize fracture networks in subsurface systems. Statistical Analysis and Data Mining: The ASA Data Science Journal (2017) `_. + +#. `\J. D. Hyman, Satish Karra, J. William Carey, Carl W. Gable, Hari Viswanathan, Esteban Rougier, and Zhou Lei. Discontinuities in effective permeability due to fracture percolation. Mechanics of Materials (2018) `_. + +#. `\S. Karra, D. O’Malley, J. D. Hyman, H.S. Viswanathan, and G. Srinivasan. Modeling flow and transport in fracture networks using graphs. Phys. Rev. E, (2018) `_. + +#. `\J. D. Hyman and J. Jimenéz-Martínez. Dispersion and mixing in three-dimensional discrete fracture networks: Nonlinear interplay between structural and hydraulic heterogeneity. Water Resources Research (2018) `_. + +#. `\D. O’Malley, S. Karra, J. D. Hyman, H. Viswanathan, and G. Srinivasan. Efficient Monte Carlo with graph-based subsurface flow and transport models. Water Resour. Res., (2018) `_. + +#. `\G. Srinivasan, J. D. Hyman, D. Osthus, B. Moore, D. O’Malley, S. Karra, E Rougier, A. Hagberg, A. Hunter, and H. S. Viswanathan. Quantifying topological uncertainty in fractured systems using graph theory and machine learning. Scientific Reports, (2018) `_. + +#. `\H. S. Viswanathan, J. D. Hyman, S. Karra, D. O’Malley, S. Srinivasan, A. Hagberg, and G. Srinivasan. Advancing graph-based algorithms for predicting flow and transport in fractured rock. Water Resour. Res., (2018) `_. + +#. `\S. Srinivasan, J. D. Hyman, S. Karra, D. O’Malley, H. Viswanathan, and G. Srinivasan. Robust system size reduction of discrete fracture networks: A multi-fidelity method that preserves transport characteristics. Computational Geosciences, 2018 `_. + +#. `\J. D. Hyman, Aric Hagberg, Dave Osthus, Shriram Srinivasan, Hari Viswanathan, and Gowri Srinivasan. Identifying backbones in three-dimensional discrete fracture net- works: A bipartite graph-based approach. Multiscale Modeling & Simulation (2018) `_. + +#. `\G. Aldrich, J. Lukasczyk, J. D. Hyman, G. Srinivasan, H. Viswanathan, C. Garth, H. Leitte, J. Ahrens, and B. Hamann. A query-based framework for searching, sorting, and exploring data ensembles. Computing in Science Engineering, (2018) `_. + +#. `\T. Sherman, J. D. Hyman, D. Bolster, N. Makedonska, and G. Srinivasan. Characterizing the impact of particle behavior at fracture intersections in three-dimensional discrete fracture networks. Physical Review E (2019) `_. + +#. `\J. D. Hyman, M. Dentz, A. Hagberg, and P. Kang. Linking structural and transport properties in three-dimensional fracture networks. J. Geophys. Res. Sol. Ea., (2019) `_. + +#. `\S. Srinivasan, S. Karra, J. D. Hyman, H. Viswanathan, and G. Srinivasan. Model reduction for fractured porous media: A machine-learning approach for identifying main flow pathways. Computational Geosciences (2018) `_. + +#. `\N. Makedonska, J.D, Hyman, E. Kwicklis, K. Birdsell, Conference Proceedings, Discrete Fracture Network Modeling and Simulation of Subsurface Transport for the Topopah Spring Aquifer at Pahute Mesa, 2nd International Discrete Fracture Network Engineering (2018) `_. + +#. `\N. Makedonska, C.W. Gable, R. Pawar, Conference Proceedings, Merging Discrete Fracture Network Meshes With 3D Continuum Meshes of Rock Matrix: A Novel Approach, 2nd International Discrete Fracture Network Engineering (2018) `_. + +#. `\A. Frampton, J.D, Hyman, L. Zou, Advective transport in discrete fracture networks with connected and disconnected textures representing internal aperture variability, Water Resources Research (2019) `_. + +#. `\J.D. Hyman, J. Jiménez-Martínez, C. W. Gable, P. H. Stauffer, and R. J. Pawar. Characterizing the Impact of Fractured Caprock Heterogeneity on Supercritical CO2 Injection. Transport in Porous Media (2019) `_. + +#. `\J.D. Hyman, H. Rajaram, S. Srinivasan, N. Makedonska, S. Karra, H. Viswanathan, H., & G. Srinivasan, (2019). Matrix diffusion in fractured media: New insights into power law scaling of breakthrough curves. Geophysical Research Letters (2019) `_. + +#. `\J.D. Hyman, M. Dentz, A. Hagberg, & P. K. Kang, (2019). Emergence of Stable Laws for First Passage Times in Three-Dimensional Random Fracture Networks. Physical Review Letters (2019) `_. + +#. `\M. R. Sweeney, C. W. Gable, S. Karra, P. H. Stauffer, R. J. Pawar, J. D. Hyman (2019). Upscaled discrete fracture matrix model (UDFM): an octree-refined continuum representation of fractured porous mediaComputational Geosciences (2019) `_. + +#. `\T. Sherman, J. D. Hyman, M. Dentz, and D. Bolster. Characterizing the influence of fracture density on network scale transport. J. Geophys. Res. Sol. Ea., (2019) `_. + +#. `\D. Osthus, J. D. Hyman, S. Karra, N. Panda, and G. Srinivasan. A probabilistic clustering approach for identifying primary subnetworks of discrete fracture networks with quantified uncertainty. SIAM/ASA Journal on Uncertainty Quantification, (2020) `_. + +#. `\V. Romano, S. Bigi, F. Carnevale, J. D. Hyman, S. Karra, A. Valocchi, M. Tartarello, and M. Battaglia. Hydraulic characterization of a fault zone from fracture distribution. Journal of Structural Geology, (2020) `_. + +#. `\S. Srinivasan, E. Cawi, J. D. Hyman, D. Osthus, A. Hagberg, H. Viswanathan, and G. Srinivasan. Physics-informed machine-learning for backbone identification in discrete fracture networks. Comput. Geosci., (2020) `_. + + +#. `\N. Makedonska, S. Karra, H.S. Viswanathan, and G.D. Guthrie,. Role of Interaction between Hydraulic and Natural Fractures on Production. Journal of Natural Gas Science and Engineering (2020). `_. + +#. `\H. Pham, R. Parashar, N. Sund, and K. Pohlmann. A Method to Represent a Well in a Three‐dimensional Discrete Fracture Network Model. Groundwater. (2020) `_. + + +#. `\M.R. Sweeney, and J.D. Hyman. Stress effects on flow and transport in three‐dimensional fracture networks. Journal of Geophysical Research: Solid Earth. (2020) `_. + +#. `\J.D. Hyman. Flow Channeling in Fracture Networks: Characterizing the Effect of Density on Preferential Flow Path Formation. Water Resources Research (2020): e2020WR027986. `_. + + +#. `\H. Pham, R. Parashar, N. Sund, and K. Pohlmann. Determination of fracture apertures via calibration of three-dimensional discrete-fracture-network models: application to Pahute Mesa, Nevada National Security Site, USA. Hydrogeol J (2020). `_. + +#. `\S. Srinivasan, D. O’Malley, J. D. Hyman, s. Karra, H. S. Viswanathan, and G. Srinivasan Transient flow modeling in fractured media using graphs. (2020) Physical Review E. `_. + +#. `\Liangchao Zou and Vladimir Cvetkovic. Inference of Transmissivity in Crystalline Rock Using Flow Logs Under Steady‐State Pumping: Impact of Multiscale Heterogeneity. Water Resources Research (2020) `_. + +#. `\P. K. Kang, J. D. Hyman, W. S. Han, & M. Dentz, Anomalous Transport in Three‐Dimensional Discrete Fracture Networks: Interplay between Aperture Heterogeneity and Injection Modes. Water Resources Research (2020) `_. + +#. `Hyman, J. D., & Dentz, M. Transport upscaling under flow heterogeneity and matrix-diffusion in three-dimensional discrete fracture networks. Advances in Water Resources (2021) `_. + +#. `T. Sherman, G. Sole-Mari, J. Hyman, M. R. Sweeney, D. Vassallo, and D. Bolster. Characterizing Reactive Transport Behavior in a Three-Dimensional Discrete Fracture Network. Transport in Porous Media (2021) `_. + +#. `S. Shriram, D. O’Malley, M. K. Mudunuru, M. R. Sweeney, J. D. Hyman, S. Karra, L. Frash et al. A machine learning framework for rapid forecasting and history matching in unconventional reservoirs. (2021) Scientific Reports `_. + + +#. `J. D. Hyman, M. R. Sweeney, L. P. Frash, J. W. Carey, and H. S. Viswanathan. Scale‐Bridging in Three‐Dimensional Fracture Networks: Characterizing the Effects of Variable Fracture Apertures on Network‐Scale Flow Channelization. Geophysical Research Letters (2021) `_. + +#. `Liangchao Zou and Vladimir Cvetkovic. Evaluation of Flow‐Log Data From Crystalline Rocks With Steady‐State Pumping and Ambient Flow. Geophysical Research Letters (2021) `_. + +#. `H. Ushijima-Mwesigwa, J. D. Hyman, A. Hagberg, I. Safro, S. Karra, C. W. Gable, M. R. Sweeney, and G. Srinivasan. Multilevel graph partitioning for three-dimensional discrete fracture network flow simulations. Mathematical Geosciences (2021) `_. + +#. `Yingtao Hu, Wenjie Xu, Liangtong Zhan, Liangchao Zou, and Yunmin Chen. "Modeling of solute transport in a fracture-matrix system with a three-dimensional discrete fracture network." Journal of Hydrology (2021) `_. + +#. `C. R. Romano, R. T. Williams; Evolution of Fault-Zone Hydromechanical Properties in Response to Different Cementation Processes. Lithosphere (2022) `_. + +#. `J. Krotz, M.R. Sweeney, C.W. Gable, J.D. Hyman, & J.M. Restrepo, (2022). Variable resolution Poisson-disk sampling for meshing discrete fracture networks. Journal of Computational and Applied Mathematics (2022) `_. + diff --git a/Documentation/sphinx-docs/build/html/_sources/pydfnFlow.rst.txt b/Documentation/sphinx-docs/build/html/_sources/pydfnFlow.rst.txt new file mode 100644 index 000000000..0dadd3402 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_sources/pydfnFlow.rst.txt @@ -0,0 +1,26 @@ +.. _dfnWorks-python-chapter-dfnFlow: + +pydfnworks: dfnFlow +======================================== + +DFN Class functions used in flow simulations (PFLOTRAN and FEHM) + +Running Flow : General +^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. automodule:: pydfnworks.dfnFlow.flow + :members: + +Running Flow: PFLOTRAN +^^^^^^^^^^^^^^^^^^^^^^^^ +.. automodule:: pydfnworks.dfnFlow.pflotran + :members: lagrit2pflotran, pflotran, parse_pflotran_vtk_python, pflotran_cleanup, write_perms_and_correct_volumes_areas, zone2ex + +Running Flow: FEHM +^^^^^^^^^^^^^^^^^^^^^^^^ +.. automodule:: pydfnworks.dfnFlow.fehm + :members: correct_stor_file, fehm + +Processing Flow +^^^^^^^^^^^^^^^^^^^^ +.. automodule:: pydfnworks.dfnFlow.mass_balance + :members: effective_perm diff --git a/Documentation/sphinx-docs/build/html/_sources/pydfnGen.rst.txt b/Documentation/sphinx-docs/build/html/_sources/pydfnGen.rst.txt new file mode 100644 index 000000000..f8662c407 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_sources/pydfnGen.rst.txt @@ -0,0 +1,200 @@ +.. _dfnWorks-python-chapter-dfnGen: + +pydfnworks: dfnGen +======================================== + +DFN Class functions used in network generation and meshing + +dfnGen +------- + +Adding Fracture Families +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. automodule:: pydfnworks.dfnGen.generation.input_checking + :members: add_fracture_family + :noindex: + +Example: + +.. code-block:: python + + DFN.add_fracture_family(shape="ell", + distribution="tpl", + alpha=1.8, + min_radius=1.0, + max_radius=5.0, + kappa=1.0, + theta=0.0, + phi=0.0, + aspect=2, + beta_distribution=1, + beta=45.0, + p32=1.1, + hy_variable='aperture', + hy_function='correlated', + hy_params={ + "alpha": 10**-5, + "beta": 0.5 + }) + + +Adding User Fractures +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. automodule:: pydfnworks.dfnGen.generation.input_checking.user_defined_fracture_functions + :members: add_user_fract + :noindex: + +Example: + +.. code-block:: python + + DFN.add_user_fract(shape='ell', + radii=.4, + aspect_ratio=1, + translation=[0.2, 0, 0.2], + normal_vector=[0, 0, 1], + number_of_vertices=8, + aperture=1.0e-5) + +Adding User Fractures From a File +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. automodule:: pydfnworks.dfnGen.generation.input_checking.user_defined_fracture_functions + :members: add_user_fract_from_file + :noindex: + +Example: + +.. code-block:: python + + DFN.add_user_fract_from_file(shape="poly", + filename = f'{src_path}/polygons.dat', + permeability = 1e-12) + + +Print Parameter Information +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Note: Some of these functions are automatically called when processing the input. + +.. automodule:: pydfnworks.dfnGen.generation.input_checking.user_defined_fracture_functions + :members: print_user_fracture_information + +.. automodule:: pydfnworks.dfnGen.generation.input_checking + :members: print_domain_parameters, print_family_information + +Processing Generator Input +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. automodule:: pydfnworks.dfnGen.generation.input_checking + :members: check_input + :noindex: + +Running the Generator +^^^^^^^^^^^^^^^^^^^^^^ +.. automodule:: pydfnworks.dfnGen.generation.generator + :members: dfn_gen, make_working_directory, create_network, grab_polygon_data + +Analysis of Generated DFN +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. automodule:: pydfnworks.dfnGen.generation.output_report.gen_output + :members: output_report + +Additional Information on the Modification of Hydraulic Properties of the DFN +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Hydraulic properties can be assigned to fractures based on four different models. One can assign hydraulic aperture :math:`b`, permeability, :math:`k`, or transmissivity :math:`T`. Below we present the functions for hydraulic aperture, but the equations for other values are the same. + +The first is a perfectly correlated model where the hydraulic property is a function of the fracture radius + +.. math:: + b = \alpha r^\beta + +The keyword for this model is correlated. + +The second is a semi-correlated correlated model where the hydraulic property is a function of the fracture radius + +.. math:: + \log_{10}(b) = \log_{10}(\alpha r^\beta) + \sigma \mathcal{N}(0,1) + +where a stochastic term is included into the correlated model +to account for uncertainty and variability between fractures of the same size. The strength of the stochastic term is determined by the variance of a log-normal distribution :math:`\sigma` and the stochastic term is an independent identically distributed random variable sampled from a normal distribution with mean 0 and variance 1, :math:`\mathcal{N}(0,1)`. This model results in a log-normal distribution of fracture transmissivities around a positively cor- related power law mean. We refer to this model as semicorrelated. + +The keyword for this model is semi-correlated. + +The third model assumes that there is no correlation between the fracture size and transmissivity and all values are independent identically distributed random variables from a log-normal distribution with speci- fied mean :math:`\mu` and variance :math:`\sigma`, + +.. math:: + \log_{10}(b) = \mu + \sigma \mathcal{N}(0,1) + +The keyword for this model is log-normal. + +The fourth model represents an assumption that in addition to no relationship between size and hydraulic properties, there is no variation between fractures + +.. math:: + b = \mu + +The keyword for this model is constant. + +Notes: + +See Hyman et al. 2016 “Fracture size and transmissivity correlations: Implications for transport simulations in sparse three-dimensional discrete fracture networks following a truncated power law distribution of fracture size” Water Resources Research for more details + +Changes in hydraulic properties are assigned when defining a fracture family or user defined fracture. User defined fractures currently only support constant hydraulic properties. + + +Modification of hydraulic properties of the DFN based on background stress field +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. automodule:: pydfnworks.dfnGen.generation.stress + :members: stress_based_apertures + +Meshing - LaGriT +----------------- + +Primary DFN meshing driver +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. automodule:: pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn + :members: mesh_network + + +Meshing helper methods +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. automodule:: pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn_helper + :members: inp2gmv, inp2vtk_python, create_mesh_links, run_lagrit_script + +.. automodule:: pydfnworks.dfnGen.meshing.add_attribute_to_mesh + :members: add_variable_to_mesh + + + +UDFM +-------- + +Creating an upscaled mesh of the DFN (UDFM) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. automodule:: pydfnworks.dfnGen.meshing.udfm.map2continuum + :members: map_to_continuum + +.. automodule:: pydfnworks.dfnGen.meshing.udfm.upscale + :members: upscale + +.. automodule:: pydfnworks.dfnGen.meshing.udfm.false_connections + :members: check_false_connections + +Map-DFN upscaling +-------------------------- +.. automodule:: pydfnworks.dfnGen.meshing.mapdfn_ecpm.mapdfn_ecpm + :members: mapdfn_ecpm + +DFM +-------- + +Creating a conforming DFM mesh DFN +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. automodule:: pydfnworks.dfnGen.meshing.dfm.mesh_dfm + :members: mesh_dfm + + + diff --git a/Documentation/sphinx-docs/build/html/_sources/pydfnGraph.rst.txt b/Documentation/sphinx-docs/build/html/_sources/pydfnGraph.rst.txt new file mode 100644 index 000000000..4965abfbb --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_sources/pydfnGraph.rst.txt @@ -0,0 +1,26 @@ +.. _dfnWorks-python-chapter-dfnGraph: + +pydfnworks: dfnGraph +======================================== + +DFN Class functions used in graph analysis and pipe-network simulations + +General Graph Functions +^^^^^^^^^^^^^^^^^^^^^^^^^ +.. automodule:: pydfnworks.dfnGraph.dfn2graph + :members: create_graph, dump_json_graph, load_json_graph, plot_graph, dump_fractures, add_fracture_source, add_fracture_target + +.. automodule:: pydfnworks.dfnGraph.pruning + :members: k_shortest_paths_backbone, greedy_edge_disjoint + + + + + +Graph-Based Flow and Transport +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. automodule:: pydfnworks.dfnGraph.graph_flow + :members: run_graph_flow + +.. automodule:: pydfnworks.dfnGraph.graph_transport + :members: run_graph_transport diff --git a/Documentation/sphinx-docs/build/html/_sources/pydfnTrans.rst.txt b/Documentation/sphinx-docs/build/html/_sources/pydfnTrans.rst.txt new file mode 100644 index 000000000..93f99325a --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_sources/pydfnTrans.rst.txt @@ -0,0 +1,11 @@ +.. _dfnWorks-python-chapter-dfnTrans: + +pydfnworks: dfnTrans +======================================== + +DFN Class functions used in particle transport simulations (DFNTrans) + +Running Transport Simulations +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. automodule:: pydfnworks.dfnTrans.transport + :members: diff --git a/Documentation/sphinx-docs/build/html/_sources/pydfnWorks-well.rst.txt b/Documentation/sphinx-docs/build/html/_sources/pydfnWorks-well.rst.txt new file mode 100644 index 000000000..1d6276a10 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_sources/pydfnWorks-well.rst.txt @@ -0,0 +1,11 @@ +.. _dfnWorks-python-chapter-well-package: + +pydfnworks: Well Package +======================================== + +DFN Class functions used for well package + +dfnWorks - Well Package +-------------------------- +.. automodule:: pydfnworks.dfnGen.well_package.wells + :members: tag_well_in_mesh, find_well_intersection_points, combine_well_boundary_zones, cleanup_wells diff --git a/Documentation/sphinx-docs/build/html/_sources/pydfnworks.rst.txt b/Documentation/sphinx-docs/build/html/_sources/pydfnworks.rst.txt new file mode 100644 index 000000000..0913ea686 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_sources/pydfnworks.rst.txt @@ -0,0 +1,226 @@ +.. _dfnWorks-python-chapter: + +pydfnworks: the dfnWorks python package +======================================== + +The pydfnworks package allows the user to run dfnWorks from the command line and call dfnWorks within other python scripts. Because pydfnworks is a package, users can call individual methods from the package. + +pydfnworks must be installed by the user prior to running dfnworks (:ref:`pydfnWorks install `) + + +Running dfnWorks from the command line using pydfnWorks +--------------------------------------------------------- +The recommended way to run dfnWorks is using a python call on the command line, or running the script in your favorite IDE. + +.. code-block:: bash + + $ python driver.py + + +The script ``driver.py`` is the python control file that contains the workflow of the particular simulation. Below is a basic example taken from the 4_user_rects_example example: + +.. code-block:: python + + from pydfnworks import * + import os + + src_path = os.getcwd() + jobname = src_path + "/output" + dfnFlow_file = src_path+ '/dfn_explicit.in' + dfnTrans_file = src_path + '/PTDFN_control.dat' + + DFN = DFNWORKS(jobname, + dfnFlow_file=dfnFlow_file, + dfnTrans_file=dfnTrans_file, + ncpu=8) + + DFN.params['domainSize']['value'] = [1.0, 1.0, 1.0] + DFN.params['h']['value'] = 0.050 + + DFN.add_user_fract(shape='rect', + radii=0.6, + translation=[-0.4, 0, 0], + normal_vector=[0, 0, 1], + permeability=1.0e-12) + + DFN.add_user_fract(shape='rect', + radii=1.0, + aspect_ratio=.65, + translation=[0, 0, 0], + normal_vector=[1, 0, 0], + permeability=1.0e-12) + + DFN.add_user_fract(shape='rect', + radii=.6, + translation=[0.4, 0, 0.2], + normal_vector=[0, 0, 1], + permeability=2.0e-12) + + DFN.add_user_fract(shape='rect', + radii=.6, + translation=[0.4, 0, -0.2], + normal_vector=[0, 0, 1], + permeability=1.0e-12) + + DFN.make_working_directory(delete=True) + DFN.check_input() + DFN.print_domain_parameters() + + DFN.create_network() + DFN.mesh_network() + + DFN.dfn_flow() + DFN.dfn_trans() + + +The DFNWORKS class +--------------------------- + +Within the python script, a DFN (discrete fracture network) object is created to control the model workflow. Data and model functions are stored on this object, allowing the user to both access information about the DFN while debugging, as well as call functions for modelling everything from network generation to transport modelling. Arguments for creating the DFN object are listed below. Additional arguments and functions required to create the DFN are discussed in other sections of this manual. + +Default Arguments: + +.. code-block:: python + + from pydfnworks import * + + DFN = DFNWORKS(jobname = None, #required + ncpu = 4, + dfnGen_file = None, #automatically generated + dfnFlow_file = None, #required for DFN.dfn_flow() + dfnTrans_file = None, #required for DFN.dfn_trans() + path = None, + prune_file = None, + flow_solver = 'PFLOTRAN', + inp_file = 'full_mesh.inp', + uge_file = 'full_mesh.uge', + mat_file = 'materialid.dat', + stor_file = None, + vtk_file = None, + num_nodes = None, + mesh_type = 'dfn', + cell_based_aperture = False) + + +jobname +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Description: (Mandatory) Path of the simulation directory. Must be a valid path. The path is stored in ``DFN.jobname`` of the DFN object + +Type: string + +Example: + +.. code-block:: python + + import os + src_path = os.getcwd() + jobname = src_path + "/output" + +ncpu +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Description: Number of processors to be used in the simulation. Stored as ``DFN.ncpu``. + +Type: integer + +Example: + +.. code-block:: python + + ncpu = 8 + + +dfnFlow_file/dfnGen_file/dfnTrans_file +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. note:: dfnGen_file is depreciated, file name is automatically specified + +Description: (Mandatory) Path of the input file containing run files for dfnGen, dfnFlow (PFLOTRAN/FEHM/AMANZI), and dfnTrans. This file is parsed and the paths contained within are stored as ``DFN.dfnGen_file``, ``DFN.dfnFlow_file``, and ``DFN.dfnTrans_file``. The local path for the files (string after the final ``/`` are stored as ``DFN.local_dfnGen_file``, ``DFN.local_dfnFlow_file``, and ``DFN.local_dfnTrans_file``. + +Type: string + +Example: + +.. code-block:: python + + dfnGen_file = 'gen_4_user_rectangles.dat' + dfnFlow_file = 'dfn_explicit.in' + dfnTrans_file = 'PTDFN_control.dat' + + +path +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Description: Path to parent directory. Useful for multiple runs using the same network with different meshing techniques, hydraulic properties, flow simulations, or pruned networks. Path is stored as ``DFN.path``. + +Type: string + +Example: + +.. code-block:: python + + path = '/dfnWorks/work/4_user_rects_example' + +prune_file +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Description: Path to ascii file of fractures to be retained (not removed) in the network after pruning. See the pruning example for a workflow demonstration. + +Type: string + +Example: + +.. code-block:: python + + prune_file = '/dfnWorks/work/pruning_example/2_core.dat' + +.. note:: To prune the network, include ``DFN.mesh_network(prune=True)`` in the python run file. + + +flow_solver +^^^^^^^^^^^^^^^ +Description: Either 'PFLOTRAN' or 'FEHM' + +Example: + +.. code-block:: python + + flow_solver = 'PFLOTRAN' + + +cell_based_aperture +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Description: Toggle if the fracture apertures are cell based. If the option is included, then the workflow will assign cell-based apertures and permeabilities from the files ``aper_node.dat`` and ``perm_node.dat``. These files consist of two columns, with a single line header value. The first column is the node number. The second column is the aperture/permeability value. See the See the in_fracture_var example for a workflow demonstration. + +Type: Boolean + +Example: + +.. code-block:: python + + cell_based_aperture = True + +additional arguments +^^^^^^^^^^^^^^^^^^^^^ +Descriptions: additional arguments that have not been described here will likely not be changed by the user. + + +pydfnWorks : Modules +------------------------ +Information about the various pieces of pydfnworks is found in + +:ref:`pydfnGen ` - Network generation, meshing, and analysis + +:ref:`pydfnFlow ` - Flow simulations using PFLOTRAN and FEHM + +:ref:`pydfnTrans ` - Particle Tracking + +:ref:`pydfnGraph ` - Graph-based analysis and pipe-network simulations + +:ref:`Well-Package ` - Well simulations + +.. note:: There are additional required arguments for network generation described in :ref:`dfnGen ` + +Detailed Doxygen Documentation +---------------------------------- +Doxygen_ + +.. _Doxygen: pydfnWorks_docs/index.html + diff --git a/Documentation/sphinx-docs/build/html/_sources/setup.rst.txt b/Documentation/sphinx-docs/build/html/_sources/setup.rst.txt new file mode 100644 index 000000000..0d3a4f7c5 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_sources/setup.rst.txt @@ -0,0 +1,198 @@ +.. _pydfnworks-setup: + +Setting and Running up dfnWorks +================================ + +Docker +------------------------------ +The easiest way to get started with dfnWorks is using our docker container (https://hub.docker.com/r/ees16/dfnworks). + +If you do not already have Docker installed on your machine, +visit `Getting Started with Docker `_. + +The dfnWorks Docker image can be pulled from DockerHub using: + +.. code-block:: bash + + $ docker pull ees16/dfnworks:latest + + +Running the dfnWorks container +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The base command for running the dfnWorks container is: + +.. code-block:: bash + + docker run -ti ees16/dfnworks:latest + +However, to exchange files between the host and container, we will need to mount +a volume. + +The option ``-v LOCAL_FOLDER:/dfnWorks/work`` will allow all files present in the +container folder ``dfnWorks/work`` to be exposed to ``LOCAL_FOLDER``, where +``LOCAL_FOLDER`` is the absolute path to a folder on your machine. + +With this is place, the final command for running the Docker container is: + +**On macOS:** + +.. code-block:: bash + + docker run -ti -v :/dfnWorks/work ees16/dfnworks:latest + +Native build from github repository +------------------------------------------ + +This document contains instructions for setting up dfnWorks natively on your +machine. To setup dfnWorks using Docker instead, see the next section. + +Clone the dnfWorks repository +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. code-block:: bash + + $ git clone https://github.com/lanl/dfnWorks.git + + +Fix paths in test directory +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Fix the pathnames in files throughout pydfnworks. This can be done automatically by running the script ``fix_paths.py``: + +.. code-block:: bash + + $ cd dfnWorks/pydfnworks/bin/ + $ python fix_paths.py + +Set the LagriT, PETSC, PFLOTRAN, Python, and FEHM paths +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +**Before executing dfnWorks,** the following paths must be set: + +- dfnWorks_PATH: the dfnWorks repository folder +- PETSC_DIR and PETSC_ARCH: PETSC environmental variables +- PFLOTRAN_EXE: Path to PFLOTRAN executable +- PYTHON_EXE: Path to python executable +- LAGRIT_EXE: Path to LaGriT executable + +.. code-block:: bash + + $ vi dfnWorks/pydfnworks/pydfnworks/paths.py + +For example: + +.. code-block:: python + + os.environ['dfnWorks_PATH'] = '/home/username/dfnWorks/' + +Alternatively, you can create a ``.dfnworksrc`` file in your home directory with the following format + +.. code-block:: bash + + { + "dfnworks_PATH": "/src/dfnworks-main/", + "PETSC_DIR": "/src/petsc", + "PETSC_ARCH": "arch-darwin-c-debug", + "PFLOTRAN_EXE": "/src/pflotran/src/pflotran/pflotran", + "PYTHON_EXE": "/anaconda3/bin/python", + "LAGRIT_EXE": "/bin/lagrit", + "FEHM_EXE": "//src/xfehm_v3.3.1" + } + + +Installing pydfnworks +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Go up into the pydfnworks sub-directory: + +.. code-block:: bash + + $ cd dfnWorks/pydfnworks/ + +Complie The pydfnWorks Package: + +.. code-block:: bash + + $ python setup.py bdist_wheel + + +Install on Your Local Machine: + +.. code-block:: bash + + $ python -m pip install dist/pydfnworks-2.6-py3-none-any.whl + +**Note that the python version in dist/ needs to be consistent with the current release** + +Installation Requirements for Native Build +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Tools that you will need to run the dfnWorks work flow are described in +this section. VisIt and ParaView, which enable visualization of desired +quantities on the DFNs, are optional, but at least one of them is highly +recommended for visualization. CMake is also optional but allows faster IO +processing using C++. + +Operating Systems +***************************** + +dfnWorks currently runs on Macs and Unix machine running Ubuntu. + +Python +***************************** + +pydfnworks uses Python 3. We recommend using +the Anaconda 3 distribution of Python, available at https://www.continuum.io/. +pydfnworks requires the following python modules: ``numpy``, ``h5py``, ``scipy``, ``matplotlib``, ``multiprocessing``, ``argparse``, ``shutil``, ``os``, ``sys``, ``networkx``, ``subprocess``, ``glob``, ``networkx``, ``fpdf``, and ``re``. + + +LaGriT +****** +The LaGriT_ meshing toolbox is used to create a high resolution computational +mesh representation of the DFN in parallel. An algorithm for conforming +Delaunay triangulation is implemented so that fracture intersections are +coincident with triangle edges in the mesh and Voronoi control volumes are +suitable for finite volume flow solvers such as FEHM and PFLOTRAN. + +.. _LaGriT: https://lagrit.lanl.gov + +PFLOTRAN +******** +PFLOTRAN_ is a massively parallel subsurface flow and reactive transport +code. PFLOTRAN solves a system of partial differential equations for +multiphase, multicomponent and multi-scale reactive flow and transport in +porous media. The code is designed to run on leadership-class supercomputers +as well as workstations and laptops. + +.. _PFLOTRAN: http://pflotran.org + +FEHM +**** +FEHM_ is a subsurface multiphase flow code developed at Los Alamos National +Laboratory. + +.. _FEHM: https://fehm.lanl.gov + +CMake +***************************** +CMake_ is an open-source, cross-platform family of tools designed to build, +test and package software. It is needed to use C++ for processing files at a +bottleneck IO step of dfnWorks. Using C++ for this file processing optional +but can greatly increase the speed of dfnWorks for large fracture networks. +Details on how to use C++ for file processing are in the scripts section of +this documentation. + +.. _CMake: https://cmake.org + +Paraview +***************************** + +Paraview_ is a parallel, open-source visualisation software. PFLOTRAN can +output in ``.xmf`` and ``.vtk`` format. These can be imported in Paraview +for visualization. While not required for running dfnWorks, Paraview is +very helpful for visualizing dfnWorks simulations. + +Instructions for downloading and installing Paraview_ can be found at +http://www.paraview.org/download/ + +.. _Paraview: http://www.paraview.org + diff --git a/Documentation/sphinx-docs/build/html/_static/_sphinx_javascript_frameworks_compat.js b/Documentation/sphinx-docs/build/html/_static/_sphinx_javascript_frameworks_compat.js new file mode 100644 index 000000000..81415803e --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_static/_sphinx_javascript_frameworks_compat.js @@ -0,0 +1,123 @@ +/* Compatability shim for jQuery and underscores.js. + * + * Copyright Sphinx contributors + * Released under the two clause BSD licence + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/Documentation/sphinx-docs/build/html/_static/basic.css b/Documentation/sphinx-docs/build/html/_static/basic.css new file mode 100644 index 000000000..f316efcb4 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_static/css/badge_only.css b/Documentation/sphinx-docs/build/html/_static/css/badge_only.css new file mode 100644 index 000000000..c718cee44 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_static/css/badge_only.css @@ -0,0 +1 @@ +.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_static/css/fonts/Roboto-Slab-Bold.woff b/Documentation/sphinx-docs/build/html/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 000000000..6cb600001 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/Documentation/sphinx-docs/build/html/_static/css/fonts/Roboto-Slab-Bold.woff2 b/Documentation/sphinx-docs/build/html/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 000000000..7059e2314 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/Documentation/sphinx-docs/build/html/_static/css/fonts/Roboto-Slab-Regular.woff b/Documentation/sphinx-docs/build/html/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 000000000..f815f63f9 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/Documentation/sphinx-docs/build/html/_static/css/fonts/Roboto-Slab-Regular.woff2 b/Documentation/sphinx-docs/build/html/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 000000000..f2c76e5bd Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/Documentation/sphinx-docs/build/html/_static/css/fonts/fontawesome-webfont.eot b/Documentation/sphinx-docs/build/html/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 000000000..e9f60ca95 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/Documentation/sphinx-docs/build/html/_static/css/fonts/fontawesome-webfont.svg b/Documentation/sphinx-docs/build/html/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 000000000..855c845e5 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Documentation/sphinx-docs/build/html/_static/css/fonts/fontawesome-webfont.ttf b/Documentation/sphinx-docs/build/html/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 000000000..35acda2fa Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/Documentation/sphinx-docs/build/html/_static/css/fonts/fontawesome-webfont.woff b/Documentation/sphinx-docs/build/html/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 000000000..400014a4b Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/Documentation/sphinx-docs/build/html/_static/css/fonts/fontawesome-webfont.woff2 b/Documentation/sphinx-docs/build/html/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 000000000..4d13fc604 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-bold-italic.woff b/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 000000000..88ad05b9f Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-bold-italic.woff differ diff --git a/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-bold-italic.woff2 b/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 000000000..c4e3d804b Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-bold.woff b/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-bold.woff new file mode 100644 index 000000000..c6dff51f0 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-bold.woff differ diff --git a/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-bold.woff2 b/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 000000000..bb195043c Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-bold.woff2 differ diff --git a/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-normal-italic.woff b/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 000000000..76114bc03 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-normal-italic.woff differ diff --git a/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-normal-italic.woff2 b/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 000000000..3404f37e2 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-normal.woff b/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-normal.woff new file mode 100644 index 000000000..ae1307ff5 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-normal.woff differ diff --git a/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-normal.woff2 b/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 000000000..3bf984332 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_static/css/fonts/lato-normal.woff2 differ diff --git a/Documentation/sphinx-docs/build/html/_static/css/theme.css b/Documentation/sphinx-docs/build/html/_static/css/theme.css new file mode 100644 index 000000000..19a446a0e --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_static/css/theme.css @@ -0,0 +1,4 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel,.rst-content .menuselection{font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .guilabel,.rst-content .menuselection{border:1px solid #7fbbe3;background:#e7f2fa}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_static/dfnworks_logo.png b/Documentation/sphinx-docs/build/html/_static/dfnworks_logo.png new file mode 100644 index 000000000..43da41a8f Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_static/dfnworks_logo.png differ diff --git a/Documentation/sphinx-docs/build/html/_static/doctools.js b/Documentation/sphinx-docs/build/html/_static/doctools.js new file mode 100644 index 000000000..4d67807d1 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/Documentation/sphinx-docs/build/html/_static/documentation_options.js b/Documentation/sphinx-docs/build/html/_static/documentation_options.js new file mode 100644 index 000000000..f53cd810e --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: 'v2.8', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_static/file.png b/Documentation/sphinx-docs/build/html/_static/file.png new file mode 100644 index 000000000..a858a410e Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_static/file.png differ diff --git a/Documentation/sphinx-docs/build/html/_static/jquery.js b/Documentation/sphinx-docs/build/html/_static/jquery.js new file mode 100644 index 000000000..c4c6022f2 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_static/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_static/js/html5shiv.min.js b/Documentation/sphinx-docs/build/html/_static/js/html5shiv.min.js new file mode 100644 index 000000000..cd1c674f5 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_static/js/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_static/js/theme.js b/Documentation/sphinx-docs/build/html/_static/js/theme.js new file mode 100644 index 000000000..1fddb6ee4 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_static/js/theme.js @@ -0,0 +1 @@ +!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/Documentation/sphinx-docs/build/html/_static/minus.png b/Documentation/sphinx-docs/build/html/_static/minus.png new file mode 100644 index 000000000..d96755fda Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_static/minus.png differ diff --git a/Documentation/sphinx-docs/build/html/_static/plus.png b/Documentation/sphinx-docs/build/html/_static/plus.png new file mode 100644 index 000000000..7107cec93 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/_static/plus.png differ diff --git a/Documentation/sphinx-docs/build/html/_static/pygments.css b/Documentation/sphinx-docs/build/html/_static/pygments.css new file mode 100644 index 000000000..691aeb82d --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_static/pygments.css @@ -0,0 +1,74 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #eeffcc; } +.highlight .c { color: #408090; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #333333 } /* Generic.Output */ +.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #208050 } /* Literal.Number */ +.highlight .s { color: #4070a0 } /* Literal.String */ +.highlight .na { color: #4070a0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60add5 } /* Name.Constant */ +.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287e } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #bb60d5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #208050 } /* Literal.Number.Bin */ +.highlight .mf { color: #208050 } /* Literal.Number.Float */ +.highlight .mh { color: #208050 } /* Literal.Number.Hex */ +.highlight .mi { color: #208050 } /* Literal.Number.Integer */ +.highlight .mo { color: #208050 } /* Literal.Number.Oct */ +.highlight .sa { color: #4070a0 } /* Literal.String.Affix */ +.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ +.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #06287e } /* Name.Function.Magic */ +.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ +.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/_static/searchtools.js b/Documentation/sphinx-docs/build/html/_static/searchtools.js new file mode 100644 index 000000000..92da3f8b2 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_static/searchtools.js @@ -0,0 +1,619 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms, anchor) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + "Search finished, found ${resultCount} page(s) matching the search query." + ).replace('${resultCount}', resultCount); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; +// Helper function used by query() to order search results. +// Each input is an array of [docname, title, anchor, descr, score, filename]. +// Order the results by score (in opposite order of appearance, since the +// `_displayNextItem` function uses pop() to retrieve items) and then alphabetically. +const _orderResultsByScoreThenName = (a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString, anchor) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + for (const removalQuery of [".headerlinks", "script", "style"]) { + htmlElement.querySelectorAll(removalQuery).forEach((el) => { el.remove() }); + } + if (anchor) { + const anchorContent = htmlElement.querySelector(`[role="main"] ${anchor}`); + if (anchorContent) return anchorContent.textContent; + + console.warn( + `Anchored content block not found. Sphinx search tries to obtain it via DOM query '[role=main] ${anchor}'. Check your theme or template.` + ); + } + + // if anchor not specified or not found, fall back to main content + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent) return docContent.textContent; + + console.warn( + "Content block not found. Sphinx search tries to obtain it via DOM query '[role=main]'. Check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + _parseQuery: (query) => { + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + return [query, searchTerms, excludedTerms, highlightTerms, objectTerms]; + }, + + /** + * execute search (requires search index to be loaded) + */ + _performSearch: (query, searchTerms, excludedTerms, highlightTerms, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // Collect multiple result groups to be sorted separately and then ordered. + // Each is an array of [docname, title, anchor, descr, score, filename]. + const normalResults = []; + const nonMainIndexResults = []; + + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase().trim(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().trim().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + normalResults.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id, isMain] of foundEntries) { + const score = Math.round(100 * queryLower.length / entry.length); + const result = [ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]; + if (isMain) { + normalResults.push(result); + } else { + nonMainIndexResults.push(result); + } + } + } + } + + // lookup as object + objectTerms.forEach((term) => + normalResults.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + normalResults.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) { + normalResults.forEach((item) => (item[4] = Scorer.score(item))); + nonMainIndexResults.forEach((item) => (item[4] = Scorer.score(item))); + } + + // Sort each group of results by score and then alphabetically by name. + normalResults.sort(_orderResultsByScoreThenName); + nonMainIndexResults.sort(_orderResultsByScoreThenName); + + // Combine the result groups in (reverse) order. + // Non-main index entries are typically arbitrary cross-references, + // so display them after other results. + let results = [...nonMainIndexResults, ...normalResults]; + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + return results.reverse(); + }, + + query: (query) => { + const [searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms] = Search._parseQuery(query); + const results = Search._performSearch(searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + if (!terms.hasOwnProperty(word)) { + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + } + if (!titleTerms.hasOwnProperty(word)) { + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: titleTerms[term], score: Scorer.partialTitle }); + }); + } + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (!fileMap.has(file)) fileMap.set(file, [word]); + else if (fileMap.get(file).indexOf(word) === -1) fileMap.get(file).push(word); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords, anchor) => { + const text = Search.htmlToText(htmlText, anchor); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/Documentation/sphinx-docs/build/html/_static/sphinx_highlight.js b/Documentation/sphinx-docs/build/html/_static/sphinx_highlight.js new file mode 100644 index 000000000..8a96c69a1 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/Documentation/sphinx-docs/build/html/applications.html b/Documentation/sphinx-docs/build/html/applications.html new file mode 100644 index 000000000..2a46eb66f --- /dev/null +++ b/Documentation/sphinx-docs/build/html/applications.html @@ -0,0 +1,177 @@ + + + + + + + Example Applications — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Example Applications

+
+

Carbon dioxide sequestration

+

dfnWorks provides the framework necessary to perform multiphase simulations (such as flow and reactive transport) at the reservoir scale. A particular application, highlighted here, is sequestering CO2 from anthropogenic sources and disposing it in geological formations such as deep saline aquifers and abandoned oil fields. Geological CO2 sequestration is one of the principal methods under consideration to reduce carbon footprint in the atmosphere due to fossil fuels (Bachu, 2002; Pacala and Socolow, 2004). For safe and sustainable long-term storage of CO2 and to prevent leaks through existing faults and fractured rock (along with the ones created during the injection process), understanding the complex physical and chemical interactions between CO2 , water (or brine) and fractured rock, is vital. dfnWorks capability to study multiphase flow in a DFN can be used to study potential CO2 migration through cap-rock, a potential risk associated with proposed subsurface storage of CO2 in saline aquifers or depleted reservoirs. Moreover, using the reactive transport capabilities of PFLOTRAN coupled with cell-based transmissivity of the DFN allows one to study dynamically changing permeability fields with mineral precipitation and dissolution due to CO2 –water interaction with rock.

+
+alternate text + +
+

Temporal evolution of supercritical |CO2| displacing water in a meter cube DFN containing 24 fractures. The DFN is initially fully saturated with water, (top left time 0 hours) and supercritical |CO2| is slowly injected into the system from the bottom of the domain to displace the water for a total time of 10 h. There is an initial flush through the system during the first hour of the simulation, and then the rate of displacement decreases.

+
+
+
+
+

Shale energy extraction

+

Hydraulic fracturing (fracking) has provided access to hydrocarbon trapped in low-permeability media, such as tight shales. The process involves injecting water at high pressures to reactivate existing fractures and also create new fractures to increase permeability of the shale allowing hydrocarbons to be extracted. However, the fundamental physics of why fracking works and its long term ramifications are not well understood. Karra et al. (2015) used dfnWorks to generate a typical production site and simulate production. Using this physics based model, they found good agreement with production field data and determined what physical mechanisms control the decline in the production curve.

+
+alternate text + +
+

Pressure in a well used for hydraulic fracturing.

+
+
+
+
+

Nuclear waste repository

+

The Swedish Nuclear Fuel and Waste Management Company (SKB) has undertaken a detailed investigation of the fractured granite at the Forsmark, Sweden site as a potential host formation for a subsurface repository for spent nuclear fuel (SKB, 2011; Hartley and Joyce, 2013). The Forsmark area is about 120 km north of Stockholm in northern Uppland, and the repository is proposed +to be constructed in crystalline bedrock at a depth of approximately 500 m. Based on the SKB site investigation, a statistical fracture model with multiple fracture sets was developed; detailed parameters of the Forsmark site model are in SKB (2011). We adopt a subset of the model that consist of three sets of background (non-deterministic) circular fractures whose orientations follow a Fisher distribution, fracture radii are sampled from a truncated power-law distribution, the transmissivity of the fractures is estimated using a power-law model based on the fracture radius, and the fracture aperture is related to the fracture size using the cubic law (Adler et al., 2012). Under such a formulation, the fracture apertures are uniform on each fracture, but vary among fractures. The network is generated in a cubic domain with sides of length one-kilometer. Dirichlet boundary conditions are imposed on the top (1 MPa) and bottom (2 MPa) of the domain to create a pressure gradient aligned with the vertical axis, and noflow boundary conditions are enforced along lateral boundaries.

+
+alternate text + +
+

Simulated particle trajectories in fractured granite at Forsmark, Sweden.

+
+
+

Sources:

+
    +
  • Adler, P.M., Thovert, J.-F., Mourzenko, V.V., 2012. Fractured Porous Media. Oxford University Press, Oxford, United Kingdom.

  • +
  • Bachu, S., 2002. Sequestration of CO2 in geological media in response to climate change: road map for site selection using the transform of the geological space into the CO2 phase space. Energy Convers. Manag. 43, 87–102.

  • +
  • Hartley, L., Joyce, S., 2013. Approaches and algorithms for groundwater flow modeling in support of site investigations and safety assessment of the Fors- mark site, Sweden. J. Hydrol. 500, 200–216.

  • +
  • Karra, S., Makedonska, N., Viswanathan, H., Painter, S., Hyman, J., 2015. Effect of advective flow in fractures and matrix diffusion on natural gas production. Water Resour. Res., under review.

  • +
  • Pacala, S., Socolow, R., 2004. Stabilization wedges: solving the climate problem for the next 50 years with current technologies. Science 305, 968–972.

  • +
  • SKB, Long-Term Safety for the Final Repository for Spent Nuclear Fuel at Forsmark. Main Report of the SR-Site Project. Technical Report SKB TR-11-01, Swedish Nuclear Fuel and Waste Management Co., Stockholm, Sweden, 2011.

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/dfnflow.html b/Documentation/sphinx-docs/build/html/dfnflow.html new file mode 100644 index 000000000..27109233f --- /dev/null +++ b/Documentation/sphinx-docs/build/html/dfnflow.html @@ -0,0 +1,279 @@ + + + + + + + dfnFlow — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

dfnFlow

+

dfnFlow involves using flow solver such as PFLOTRAN or FEHM. PFLOTRAN is recommended if a large number of fractures ( > O(1000)) are involved in a network. Using the function calls that are part of pydfnworks, one can create the mesh files needed to run PFLOTRAN. This will involve creating unstructured mesh file *uge as well as the boundary *ex files. Please see the PFLOTRAN user manual at http://www.pflotran.org under unstructured explicit format usage for further details. An example input file for PFLOTRAN is provided in the repository. Please use this as a starting point to build your input deck.

+

Below is a sample input file. Refer to the PFLOTRAN user manual at http://www.pflotran.org for input parameter descriptions.

+
# Jan 13, 2014
+# Nataliia Makedonska, Satish Karra, LANL
+#================================================
+
+SIMULATION
+  SIMULATION_TYPE SUBSURFACE
+  PROCESS_MODELS
+    SUBSURFACE_FLOW flow
+      MODE RICHARDS
+    /
+  /
+END
+SUBSURFACE
+
+DFN
+
+#=========================== discretization ===================================
+GRID
+  TYPE unstructured_explicit full_mesh_vol_area.uge
+  GRAVITY 0.d0 0.d0 0.d0
+END
+
+
+#=========================== fluid properties =================================
+FLUID_PROPERTY
+  DIFFUSION_COEFFICIENT 1.d-9
+END
+
+DATASET Permeability
+  FILENAME dfn_properties.h5
+END
+
+#=========================== material properties ==============================
+MATERIAL_PROPERTY soil1
+  ID 1
+  POROSITY 0.25d0
+  TORTUOSITY 0.5d0
+  CHARACTERISTIC_CURVES default
+  PERMEABILITY
+    DATASET Permeability
+  /
+END
+
+
+#=========================== characteristic curves ============================
+CHARACTERISTIC_CURVES default
+  SATURATION_FUNCTION VAN_GENUCHTEN
+    M 0.5d0
+    ALPHA  1.d-4
+    LIQUID_RESIDUAL_SATURATION 0.1d0
+    MAX_CAPILLARY_PRESSURE 1.d8
+  /
+  PERMEABILITY_FUNCTION MUALEM_VG_LIQ
+    M 0.5d0
+    LIQUID_RESIDUAL_SATURATION 0.1d0
+  /
+END
+
+#=========================== output options ===================================
+OUTPUT
+  TIMES s 0.01 0.05 0.1 0.2 0.5 1
+#  FORMAT TECPLOT BLOCK
+  PRINT_PRIMAL_GRID
+  FORMAT VTK
+  MASS_FLOWRATE
+  MASS_BALANCE
+  VARIABLES
+    LIQUID_PRESSURE
+    PERMEABILITY
+  /
+END
+
+#=========================== times ============================================
+TIME
+  INITIAL_TIMESTEP_SIZE  1.d-8 s
+  FINAL_TIME 1.d0 d==
+  MAXIMUM_TIMESTEP_SIZE 10.d0 d
+  STEADY_STATE
+END
+
+# REFERENCE_PRESSURE 1500000.
+
+#=========================== regions ==========================================
+REGION All
+  COORDINATES
+    -1.d20 -1.d20 -1.d20
+    1.d20 1.d20 1.d20
+  /
+END
+
+REGION inflow
+  FILE pboundary_left_w.ex
+END
+
+REGION outflow
+  FILE pboundary_right_e.ex
+END
+
+#=========================== flow conditions ==================================
+FLOW_CONDITION initial
+  TYPE
+     PRESSURE dirichlet
+  /
+  PRESSURE 1.01325d6
+END
+
+
+FLOW_CONDITION outflow
+  TYPE
+     PRESSURE dirichlet
+  /
+  PRESSURE 1.d6
+END
+
+FLOW_CONDITION inflow
+  TYPE
+    PRESSURE dirichlet
+  /
+  PRESSURE 2.d6
+END
+
+#=========================== condition couplers ===============================
+# initial condition
+INITIAL_CONDITION
+  FLOW_CONDITION initial
+  REGION All
+END
+
+
+BOUNDARY_CONDITION INFLOW
+  FLOW_CONDITION inflow
+  REGION inflow
+END
+
+BOUNDARY_CONDITION OUTFLOW
+  FLOW_CONDITION outflow
+  REGION outflow
+END
+
+#=========================== stratigraphy couplers ============================
+STRATA
+  REGION All
+  MATERIAL soil1
+END
+
+END_SUBSURFACE
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/dfngen.html b/Documentation/sphinx-docs/build/html/dfngen.html new file mode 100644 index 000000000..8dad0b0b2 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/dfngen.html @@ -0,0 +1,2580 @@ + + + + + + + dfnGen - C++ Generation Code — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

dfnGen - C++ Generation Code

+

dfnGen creates the discrete fracture networks using the feature rejection algorithm for meshing (FRAM). Fractures can be created stochastically or as deterministic features.

+

The detailed description of FRAM and the implemented methodology is in J. D. Hyman, C. W. Gable, S. L. Painter, and N. Makedonska. Conforming Delaunay triangulation of stochastically generated three dimensional discrete fracture networks: A feature rejection algorithm for meshing strategy. SIAM J. Sci. Comput., 36(4):A1871–A1894, 2014.

+
+

Domain Parameters

+

The following parameters define the domain. All units are in SI (meters for length).

+
+

Note

+

Parameters with (Mandatory) label must be present in python driver script for simulations to run.

+
+
+
+

domainSize

+

Description: (Mandatory) Defines the domain size, which is centered at the origin (0,0,0). The first entry is span in x (east/west), the second entry is span in y (North/South), and the third entry is span in z (Top/Bottom).

+

Type: List of three floats

+

Default : None

+

Example:

+
DFN.parameters['domainSize']['value'] = [10.0,5.0,20.0]
+# Create a domain of 10 m by 5 m by 20.
+# Minimum/Maximum x is -5/+5
+# Minimum/Maximum in y is -2.5/+2.5
+# Minimum/Maximum in z is -10/+10.
+
+
+
+

Note

+

The minimum and maximum in each direction is 1/2 the input value.

+
+
+
+
+

domainSizeIncrease

+

Description: Temporary domainSize increase for inserting fracture centers outside of the domain defined by domainSize. After generation is complete, the domain is truncated back to domainSize. First entry is expansion in x (east/west), second entry is expansion in y (North/South), and third entry is expansion in z (Top/Bottom). This is used to help mitigate edge density effects.

+

Type: List of three floats

+

Default: [0,0,0]

+

Example:

+
DFN.params['domainSizeIncrease']['value'] = [2,1,5]
+# Increase the domain-size by:
+# adding 1 to the +x, and subtracting 1 to the -x
+# adding 0.5 to +y, and subtracting -0.5 to -y
+# adding 2.5 to +z, and subtracting -2.5 to -z
+
+
+
+

Note

+

The domain size increase in each direction must be less than 1/2 the domain size in that direction.

+
+
+

Tip

+

A good rule of thumb is to set the expansion length to be at least the radius of the largest fracture.

+
+
+
+
+

numOfLayers

+

Description: Defines the number of stratographic layers in the domain. If numOfLayers is 0, then there are no layers. For N layers, there must be N sets of minimum and maximum heights defined in layers. Each stochastic fracture set is assigned to a layer when creating a fracture family (See pydfnGen).

+

Type: Non-Negative Integer (N > 0)

+

Default: 0

+

Example:

+
DFN.params['numOfLayers']['value'] = 2 # There will be two layers in the domain
+
+
+
+
+
+

layers

+

Description. Defines the lower and upper limits for each layer. The first layer listed is layer 1, the second is layer 2, etc. Every stochastic families must be assigned to a layer. If the family is assigned to layer 0, then the family in generated through the entire domain.

+

Type: List of numOfLayers lists with two elements. [zMin, zMax]

+

Default: None

+

Example:

+
DFN.params['layers']['value'] =  [[-50, -30],  # Minimum and Maximum height of layer 1 is -50 m and -30 m
+                                    [10, 40]] # Minimum and Maximum height of layer 2 is 10 m and 40 m
+
+
+
+

Note

+
+
First entry (zMin) must be less than second entry (zMax)
+
Layers can overlap
+
+
+
+
+
+

numOfRegions

+

Description: Defines the number of cuboid regions in the domain. If numOfRegions is 0, then there are no regions. There must be N sets of defined by regions. Each stochastic fracture set is assigned to a region during fracture family creation (See pydfnGen).

+

Type: Non-Negative Integer (N > 0)

+

Default: 0

+

Example:

+
DFN.params['numOfRegions']['value'] = 1 # There will be one region in the domain
+
+
+
+
+
+

regions

+

Description: Defines the bounding box of each region. The first region listed is region 1, the region is region 2, etc. Stochastic families must be assigned to theses regions. If the family is assigned to region 0, then the family in generated through the entire domain.

+

Type: List of numOfRegions lists with six elements. [minX, maxX, minY, maxY, minZ, maxZ].

+

Default: None

+

Example:

+
DFN.params['regions']['value'] = [[-5, 5, -10, 10, -20, 10],
+                                    [0, 10, -5, 15, 10, 20]]
+                                    # Will create two regions for sampling
+                                    # The first region with
+                                    # x-min: -5, x-max: 5
+                                    # y-min: -10, y-max: 10
+                                    # z-min: -20, z-max: 10
+
+
+
+

Note

+
+
Min/Max values for each direction do not need to be the same.
+
Minimum value must be less than the maximum value in each direction
+
Regions can overlap
+
+
+
+
+
+

ignoreBoundaryFaces

+

Description: Selection of using the boundary faces option.

+

Type: boolean

+
+
False: use boundaryFaces option
+
True: ignore boundaryFaces option and keep all clusters
+
+

Example:

+
DFN.params['ignoreBoundaryFaces']['value'] = True
+
+
+
+

Warning

+

All clusters are retained only if keepOnlyLargestCluster is set to 0.

+
+
+
+
+

boundaryFaces

+

Description: Selects domain boundaries for flow. The generation will only keep clusters of fractures with connections to domain boundaries which are set to 1.

+

Type: list of six boolean values corresponding to each face of the domain.

+
+
+
boundaryFaces[0] = +X domain boundary
+
boundaryFaces[1] = -X domain boundary
+
boundaryFaces[2] = +Y domain boundary
+
boundaryFaces[3] = -Y domain boundary
+
boundaryFaces[4] = +Z domain boundary
+
boundaryFaces[5] = -Z domain boundary
+
+
+

Default: [1,1,0,0,0,0]

+

Example:

+
DFN.params['boundaryFaces']['value'] = [1,1,0,0,0,0] # Keep fractures within a cluster that connect the X boundaries
+
+
+
+

Warning

+

ignoreBoundaryFaces must be False (default) when using this feature

+
+
+
+
+
+

General Network Generation Parameters

+

The following parameters define the general network properties.

+
+

Note

+

parameters with (Mandatory) label must be present in python driver script for simulations to run.

+
+
+
+

stopCondition

+

Description: Selection criteria for when network generation stops.

+

Type: boolean (0/1)

+

Default: 1

+
+
0: stop generation once nPoly fractures are accepted
+
1: stop generation once all fracture family p32 values have been meet
+
+

Example:

+
DFN.params['stopCondition']['value'] = 1
+
+
+
+

Note

+

p32 values are defined for each family during the creation of the fracture family. If stopCondition = 0 the famProb of a fracture belonging to a family is set during the creation of the fracture family (See pydfnGen).

+
+
+
+
+

nPoly

+

Description: The total number of fractures requested in the domain. dfnGen will stop generation once there are nPoly number of fractures.

+

Type: Positive Integer (nPoly > 0)

+

Default: None

+

Example:

+
DFN.params['nPoly']['value'] = 100 # Stop generation once 100 fractures are accepted into the network
+
+
+
+

Note

+

Only used if stopCondition is set to 0

+
+
+
+
+

famProb

+

Description: Probability of occurrence for each family of stochastically generated fractures. Values of famProb elements must add up to 1.0. The probabilities are saved in order of families starting with all stochastic ellipses, and then all stochastic rectangles.

+

Type: List of length number of stochastic fracture families (nFamEll + nFamRect)

+

This list is automatically generated. The values are defined with the creation of each fracture family (See pydfnGen).

+
+

Note

+

User defined ellipses, rectangles, and polygons are inserted into the domain prior to any stochastic fractures. However, there is a possibility they will be rejected if FRAM constraints are not met.

+
+
+
+
+

orientationOption

+

Description: Selection of fracture family orientation definition.

+

Type: Value of 0,1,2

+
+
0 : Spherical Coordinates
+
1 : Trend / Plunge
+
2 : Dip / Strike
+
+

This value is set automatically with the definition of fracture families (See pydfnGen).

+
+

Note

+
+
For spherical coordinates, values are defined using the function parameters theta/phi.
+
For Trend/Plunge, values are defined using trend/plunge.
+
For Dip/Strike, values are defined using dip/strike.
+
+
+
+

Warning

+
+
When using Trend / Plunge or Dip / Strike, angleOption must be set to degree (default), angleOption = ‘degree’
+
+
+
+
+
+

angleOption

+

Description: Selection of fracture family angle units. All stochastically generated fracture families will use the specified units

+

Type: String of either ‘degree’ or ‘radian’

+

Default: ‘degree’

+

Example:

+
DFN.params['angleOption']['value'] = 'radian'
+
+
+
+

Warning

+
+
When using Trend / Plunge or Dip / Strike, angleOption must be set to degree (default), angleOption = ‘degree’
+
+
+
+
+
+

h

+

Description: (Mandatory) Minimum feature size accepted into the network.

+

Type: Positive float

+
+

Note

+
+
The following constraints are imposed on h to keep the final mesh size reasonable, unless disableFram is turned on.
+
+
+
1. h must be greater than 10^{-5} \cdot \sqrt{x^2 + y^2 + z^2} where x,y,z are the elements of domainSize.
+
2. h must be smaller than 1/10th the minimum fracture size
+
3. h must be larger than 1/1000th than minimum fracture size
+
4. h must be non-zero
+
+
+

Default: None

+

Example:

+
DFN.params['h']['value'] = .1
+
+
+ +
+
+
+

disableFram

+
+

Danger

+

disableFram: If FRAM is turned off (disableFram: True) the resulting network can only be meshed using the coarse visual mode. You cannot mesh DFN or run flow and transport if the network is generated with disableFram: True.

+
+

Description: (Mandatory) Turn FRAM on/off. Having FRAM on is required for full DFN capabilities of meshing, flow, and transport. If FRAM is off then capabilities will be limited.

+

Type: boolean

+
+
False: FRAM is on
+
True: FRAM is off
+
+

Default: False

+

Example:

+
DFN.params['disableFram']['value'] = False
+
+
+
+

Note

+

disableFram: True and visualizationMode :1 are recommended if the intention is to use an upscaled octree mesh using the UDFM module in pydfnWorks.

+
+
+
+
+

printRejectReasons

+

Description: Option to print rejection information to screen during network generation.

+

Type: boolean

+
+
False: off. Limited rejection information will be printed to screen during generation.
+
True: on. Detailed fracture information will be printed to screen during generation.
+
+

Default: False

+

Example:

+
DFN.params['printRejectReasons']['value'] = True
+
+
+
+

Tip

+

Turning this feature on is useful for debugging and initial network construction. Having this turned off is more efficient for network generation.

+
+
+
+
+

rejectsPerFracture

+

Description: If fracture is rejected, it will be re-translated to a new position rejectsPerFracture number of times. Increasing this value can help hit distribution targets for stochastic families.

+

Type: Positive Integer

+

Default: 10

+

Example:

+
DFN.params['rejectsPerFracture']['value'] = 10 # If a fracture is rejected, it will be translated to a new point in the domain 10 times before being completely rejected
+
+
+
+

Note

+

Default is 10. Set equal to 1 to ignore.

+
+
+
+
+

radiiListIncrease

+

Description: Increases the length of the radii list in the sampling queue by this percentage. Fracture radii are sampled and ordered (largest to smallest) prior to beginning network generation. If the target distributions are not being properly resolved due to rejection, then increasing this value can help provide a more uniform representation of the distribution. Once the original list is exhausted, then fracture radii are sampled from the distribution at random and only smaller fractures are likely to be accepted.

+

Type: Positive Double

+

Default: 0.1

+

Example:

+
DFN.params['radiiListIncrease']['value'] = 0.10 # Increase the length of the possible samples by 10%.
+
+
+
+

Note

+

Set to 0 to ignore.

+
+
+

Tip

+

Examine the dfnGen output report to check if the prescribed distributions are being properly resolved. Run DFN.output_report() in the python work file after generation is complete to generate the output report.

+
+
+
+
+

visualizationMode

+
+

Warning

+

No longer supported. Selection of visual mode should be done using the pydfnWorks function DFN.mesh_network(visual_mode=True)

+
+

Description: Selection if you want to mesh to be coarse, for quick visualization but cannot run flow and transport, or standard mesh.

+

Type: boolean

+
+
False: Create full DFN mesh (full_mesh.inp) for flow and transport
+
True: Create reduced DFN mesh (reduced_mesh.inp) for quick visualization
+
+

Default: False

+

Example:

+
DFN.params['visualizationMode']['value'] = False
+
+
+
+
+
+

seed

+

Description: Seed for random generator. Setting the seed equal to 0 will seed off the clock and a unique network will be produced. Setting the seed equal to a value > 0 will create the same network every time, which is useful for reproducibility.

+

Type: Non-negative integer

+

Default: 1

+

Example:

+
DFN.params['seed']['value'] = 42069
+
+
+
+

Tip

+

If you set seed to 0, the seed used in the generation is saved in the file DFN_output.txt created by dfnGen.

+
+
+
+
+

keepOnlyLargestCluster

+

Description: Selection to retain multiple clusters that connect boundaries or only the largest cluster. The largest cluster is defined by the number of fractures in the cluster.

+

Type: boolean

+
+
False: Keep all clusters that connect the specified boundary faces in boundaryFaces
+
True: Keep only the largest cluster that connects the specified boundary faces in boundaryFaces
+
+

Default: True

+

Example:

+
DFN.params['keepOnlyLargestCluster']['value'] = False
+
+
+
+
+
+

keepIsolatedFractures

+

Description: Selection to keep isolated fractures in the domain after generation is complete.

+

Type: boolean

+
+
False: Remove isolated fractures from the domain
+
True: Keep isolated in the domain.
+
+

Default: False

+

Example:

+
DFN.params['keepIsolatedFractures']['value'] = False
+
+
+
+

Note

+

Isolated fractures do not contribute to flow in the DFN as they are not connected to flow boundaries. If you are running a DFN, keepIsolatedFractures should be set to False. You can keep isolated fractures in the domain for UDFM meshing.

+
+
+

Danger

+

Full DFN-meshing will fail if isolated fractures are not removed. Reduced meshing for visualization can still be performed.

+
+
+
+
+

tripleIntersections

+

Description: Selection of whether triple intersection are accepted into the network.

+

Type: boolean

+
+
False: Reject all triple intersections
+
True: Accept triple intersections that meet FRAM criteria.
+
+

Default: False

+

Example:

+
DFN.params['tripleIntersections']['value'] = True
+
+
+
+

Note

+

Even if tripleIntersections = True, triple intersections can be rejected if they create a feature on the network smaller than h.

+
+
+

Warning

+

dfnTrans does not support triple intersections.

+
+
+
+
+

removeFracturesLessThan

+

Description: All fractures with radius less than removeFracturesLessThan are removed from the network after generation is complete.

+

Type: Non-Negative double

+

Default: 0

+

Example:

+
DFN.params['removeFracturesLessThan']['value'] = 5 # Remove all fracture with radius less than 5 meters.
+
+
+
+

Note

+

The lower cutoff of fracture size is defined using fracture family generation, e.g., emin for ellipses sampled from a truncated powerlaw. If this parameter is non-zero, then the network will be generated with fractures down to the lower cutoff, but only those with a radius greater than removeFracturesLessThan will be output for meshing.

+
+
+
+
+

insertUserRectanglesFirst

+

Description: Select order for how user defined rectangles and user defined ellipses are inserted into the domain.

+

Type: boolean

+
+
False: Insert user defined ellipses first
+
True: Insert user defined rectangles first
+
+

Default: True

+

Example:

+
DFN.params['insertUserRectanglesFirst']['value'] = False
+
+
+
+

Note

+

User defined fractures (ellipses, rectangles, and polygons) are always inserted prior to stochastic fractures.

+
+
+
+
+

forceLargeFractures

+

Description: Insert the largest fracture from each family into the domain prior to sampling sequential from family based on their respective probabilities.

+

Type: boolean

+
+
False: Do not force the largest fractures
+
True: Force the largest fractures
+
+

Default: False

+
DFN.params['forceLargeFractures']['value'] = True
+
+
+
+

Warning

+

No Longer Supported. Fractures are sorted by size prior to being inserted into the domain. Larger fractures are inserted first to minimize rejections.

+
+
+
+
+
+

General Network Output Parameters

+
+

outputAllRadii

+

Description: Create an output file of all fracture radii, both accepted and rejected fractures.

+
+
Filename: radii_AllAccepted.dat
+
Format: xRadius yRadius Distribution # (-2 = userPolygon, -1 = userRectangle, 0 = userEllipse, > 0 is family in order of famProb)
+
+

Type: boolean

+
+
False: Do not create file
+
True: Create file
+
+

Default: False

+

Example

+
DFN.params['outputAllRadii']['value'] = False
+
+
+
+
+
+

outputAcceptedRadiiPerFamily

+

Description: Create one file that contains the radius of every fracture per family prior to isolated fractures removed.

+
+
Filename: radii/radii_AllAccepted_Fam_1.dat
+
Format: xRadius yRadius DistributionNumber (-2 = userPolygon, -1 = userRectangle, 0 = userEllipse, > 0 is family in order of famProb)
+
+

Type: boolean

+
+
False: Do not create file
+
True: Create file
+
+

Default: False

+

Example:

+
DFN.params['outputAcceptedRadiiPerFamily']['value'] = False
+
+
+
+
+
+

outputFinalRadiiPerFamily

+

Description: Create one file that contains the radius of every fracture per family after to isolated fractures removed.

+
+
Filename: radii/radii_Final_Fam_1.dat
+
Format: xRadius yRadius DistributionNumber (-2 = userPolygon, -1 = userRectangle, 0 = userEllipse, > 0 is family in order of famProb)
+
+

Type: boolean

+
+
False: Do not create file
+
True: Create file
+
+

Default: False

+

Example:

+
DFN.params['outputFinalRadiiPerFamily']['value'] = False
+
+
+
+
+
+
+

Fracture Family Generation Parameters: Ellipse

+

This section describes generation parameters for families of disc-shaped fractures. The number of elements in each parameter matches the number of ellipse families in nFamEll. The index of the elements corresponds to the fracture family. The first element of each parameter corresponds to the first family, the second element corresponds to the second family, etc.

+
+

Warning

+

The parameters shown in this section are automatically written to the parameter dictionary (DFN.params) when defining fracture families. Documentation here is meant to provide additional information on the definition of each parameter in the parameter dictionary. For information on setting these parameters see pydfnGen

+
+
+

Ellipse: General Parameters

+
+

nFamEll

+

Description: Number of ellipse families

+

Type: Non-Negative Integer

+

Default: 0

+

Example:

+
DFN.params['nFamEll']['value'] = 3 # There will be 3 ellipse families
+
+
+
+
+
+

eLayer

+

Description: Assign each ellipse family to a layer in domain.

+

Type: list of nFamEll integers

+

Example:

+
DFN.params['eLayer']['value'] = [0,2,1]
+# Family 1 is assigned to the whole domain
+# Family 2 is assigned to layer 2
+# Family 3 is assigned to layer 1
+
+
+
+

Note

+

Layer 0 is the entire domain. Numbers > 0 correspond to those defined in layers.

+
+
+

Warning

+

Families can only be assigned to either a layer or a region, not both.

+
+
+
+
+

eRegion

+

Description: Assign each ellipse family to a region in domain.

+

Type: list of nFamEll integers

+

Example:

+
DFN.params['eRegion']['value'] = [0,2,1]
+# Family 1 is assigned to the whole domain
+# Family 2 is assigned to region 2
+# Family 3 is assigned to region 1
+
+
+
+

Note

+

Region 0 is the entire domain. Numbers > 0 correspond to those defined in regions.

+
+
+

Warning

+

Families can only be assigned to either a layer or a region, not both.

+
+
+
+
+

e_p32Targets

+

Description: Target fracture intensity per family. Fracture intensity P_{32} [\text{m}^{-1}] is defined as total surface area of each fracture family divided by the total domain volume. Fractures from each family are inserted into the domain until provided target values are obtained. Generation stops once all desired fracture intensity are obtained.

+

Type: list of nFamEll floats

+

Example:

+
DFN.params['e_p32Targets']['value'] = [0.02,0.4,0.05]
+# Family 1 has a target p32 of 0.02
+# Family 2 has a target p32 of 0.4
+# Family 3 has a target p32 of 0.05
+
+
+
+

Note

+

Only used when stopCondition = 1

+
+
+

Warning

+

The fracture surface area is defined using both sides of a fracture.

+
+
+
+
+

enumPoints

+

Description: Number of vertices defining the boundary of each elliptical fracture

+

Type: list of nFamEll integers

+

Example:

+
DFN.params['enumPoints']['value'] = [8,12,16]
+# Fractures from family 1 are defined using 8 points
+# Fractures from family 2 are defined using 12 points
+# Fractures from family 3 are defined using 16 points
+
+
+
+

Note

+
+
1. Values must be greater than 4, which corresponds to a rectangle
+
2. Increasing this value lead to more challenging acceptance criteria via FRAM due to smaller edge lengths between vertices on the fracture boundary
+
3. Suggested value: 8
+
+
+
+
+
+

easpect

+

Description: Aspect ratio of fractures

+

Type: list of nFamEll floats

+

Example:

+
DFN.params['easpect']['value'] = [1,2,0.5]
+# Family 1 has an aspect ratio of 1 (circles)
+# Family 2 has an aspect ratio of 2 - y radius is twice the x radius
+# Family 3 has an aspect ratio of 0.5 - y radius is 1/2 the x radius
+
+
+
+

Note

+

A value of 1 makes circles

+
+
+

Tip

+

As the aspect ratio increases, the shape of the ellipse can degrade accuracy unless enumPoints is also increased

+
+
+
+
+
+

Ellipse: Fracture Orientation

+

The fracture orientations are sampled from the three-dimensional von Mises-Fisher distribution,

+
+

f({\bf x}; {\boldsymbol \mu}, \kappa ) = \frac{ \kappa \exp( \kappa {\boldsymbol \mu}^{T} {\bf x} )}{ 4 \pi \sinh(\kappa)}~.

+

where {\boldsymbol \mu} is the mean orientation vector and T denotes transpose. +The distribution is sampled using the algorithm provided Simulation of the von Mises Fisher distribution Communications in statistics-simulation and computation 23.1 (1994): 157-164. by Andrew Wood..

+

dfnGen accepts spherical coordinates (\theta/\phi), Trend/Plunge, or Dip/Strike to define the mean orientation of a fracture family.

+
+

Tip

+

orientationOption indicates which of these options are used. This is automatically set based on which option is used during fracture family parameter generation. The same option must be used for all families.

+
+
0 : Spherical Coordinate (Theta/Phi)
+
1 : Trend / Plunge
+
2 : Dip / Strike.
+
+
+
+
+

ekappa

+

Description: The concentration parameter of the von Mises-Fisher distribution, which determines the degree of clustering around the mean orientation.

+

Type: list of nFamEll floats

+

Example:

+
DFN.params['ekappa']['value'] = [0.1, 20, 17]
+# Fracture Family 1 has a theta value of 45 degrees
+# Fracture Family 2 has a theta value of 78 degrees
+# Fracture Family 3 has a theta value of 0 degrees
+
+
+
+

Note

+

Values of \kappa approaching zero result in a uniform distribution of points on the sphere. Larger values create points with a small deviation from mean direction.

+
+
+

Warning

+

The numerical method for sampling the von Mises-Fisher distribution becomes unstable for values greater than 100.

+
+
+
+
+

Ellipse: Spherical Coordinates

+

The mean normal vector of the fracture family \vec{n} is related to the spherical coordinates \theta and \phi by

+
+

\vec{n}_x & = \sin(\theta) \cos(\phi)\\

+
+

\vec{n}_y & = \sin(\theta) \sin(\phi)\\

+
+

\vec{n}_z & = \cos(\theta)

+
+
etheta
+

Description: Angle the normal vector of the fracture makes with the z-axis

+

Type: list of nFamEll floats

+

Example:

+
DFN.params['etheta']['value'] = [45, 78, 0]
+# Fracture Family 1 has a theta value of 45 degrees
+# Fracture Family 2 has a theta value of 78 degrees
+# Fracture Family 3 has a theta value of 0 degrees
+
+
+
+

Note

+

Both radians and degrees are supported. Use angleOption to select one. If angleOption is set to radians angleOption = ‘radian’, and the value provided must be less than 2 \pi.

+
+
+
+
+
ephi
+

Description: Angle that the projection of the normal vector of a fracture onto the x-y plane makes with the x-axis.

+

Type: list of nFamEll float

+

Example:

+
DFN.params['ephi']['value'] =  [0, 56, 12]
+# Fracture Family 1 has a phi value of 0 degrees
+# Fracture Family 2 has a phi value of 56 degrees
+# Fracture Family 3 has a phi value of 12 degrees
+
+
+
+

Note

+

Both radians and degrees are supported. Use angleOption to select one. If angleOption is set to radians angleOption = ‘radian’, then the value provided must be less than 2 \pi.

+
+
+
+
+
+

Ellipse: Trend & Plunge

+

The mean normal vector of the fracture family \vec{n} is related to trend and plunge by

+
+

\vec{n}_x & = \cos(\text{trend}) \cos(\text{plunge})\\

+
+

\vec{n}_y & = \sin(\text{trend}) \cos(\text{plunge})\\

+
+

\vec{n}_z & = \sin(\text{trend})

+
+
etrend
+

Description: Trend of fracture families

+

Type: list of nFamEll float

+

Example

+
DFN.params['etrend']['value'] = [0, 56, 12]
+# Fracture Family 1 has a trend value of 0 degrees
+# Fracture Family 2 has a trend value of 56 degrees
+# Fracture Family 3 has a trend value of 12 degrees
+
+
+
+

Note

+

angleOption must be set to degree (angleOption = ‘degree’) to use Trend & Plunge

+
+
+
+
+
eplunge
+

Description: Plunge of fracture families

+

Type: list of nFamEll float

+

Example

+
DFN.params['eplunge']['value'] = [0, 56, 12]
+# Fracture Family 1 has a plunge value of 0 degrees
+# Fracture Family 2 has a plunge value of 56 degrees
+# Fracture Family 3 has a plunge value of 12 degrees
+
+
+
+

Note

+

angleOption must be set to degree (angleOption = ‘degree’) to use Trend & Plunge

+
+
+
+
+
+

Ellipse: Dip & Strike

+

The mean normal vector of the fracture family \vec{n} is related to dip and strike by

+
+

\vec{n}_x & = \sin(\text{dip}) \sin(\text{strike})\\

+
+

\vec{n}_y & = -\sin(\text{dip}) \cos(\text{strike})\\

+
+

\vec{n}_z & = \cos(\text{dip})

+

+
+
estrike
+

Description: Strike of fracture families

+

Type: list of nFamEll float

+

Example

+
DFN.params['estrike']['value'] = [0, 56, 12]
+# Fracture Family 1 has a strike value of 0 degrees
+# Fracture Family 2 has a strike value of 56 degrees
+# Fracture Family 3 has a strike value of 12 degrees
+
+
+
+

Note

+

angleOption must be set to degree (angleOption = ‘degree’) to use Dip & Strike

+
+
+
+
+
edip
+

Description: Dip of fracture families

+

Type: list of nFamEll float

+

Example

+
DFN.params['edip']['value'] = [0, 56, 12]
+# Fracture Family 1 has a dip value of 0 degrees
+# Fracture Family 2 has a dip value of 56 degrees
+# Fracture Family 3 has a dip value of 12 degrees
+
+
+
+

Note

+

angleOption must be set to degree (angleOption = ‘degree’) to use Dip & Strike

+
+
+
+
+
+

Ellipse: In Plane Rotation

+
+
ebetaDistribution
+

Description: Prescribe a rotation around each fracture’s normal vector, with the fracture centered on x-y plane at the origin

+

Type: list of nFamEll boolean values

+
+
0: Uniform distribution on [0, 2 \pi )
+
1: Constant rotation specified by ebeta
+
+
DFN.params['ebetaDistribution']['value'] = [0, 1, 1]
+# Fracture Family 1 will have a random rotation
+# Fracture Family 2 will have a constant angle of rotation defined in the first entry of ebeta
+# Fracture Family 3 will have a constant angle of rotation defined in the second entry of ebeta
+
+
+
+
+
+
ebeta
+

Description: Values for constant angle of rotation around the normal vector

+

Type: list of boolean (0/1)

+

Example:

+
DFN.params['ebetaDistribution']['value'] = [45, 270] # For ebetaDistribution: [0, 1, 1]
+# Fracture Family 2 will have a constant angle of rotation of 45 degrees
+# Fracture Family 3 will have a constant angle of rotation of 270 degrees
+
+
+
+

Note

+
+
1. The length of ebeta corresponds to the number of non-zero entries in ebetaDistribution
+
2. angleOption defines if the values are in radians or degrees
+
+
+
+
+
+
+

Ellipse: Fracture Radius Distributions

+

Fracture radii can be defined using four different distributions: (1) Log-Normal, (2) Truncated Power-law, (3) Exponential, and (4) Constant. Minimum and maximum values must be provided for 1-3 along with the distribution parameters.

+
+
+

edistr

+

Description: Assigns fracture radius distribution for each family

+

Type: list of nFamEll Integers (1,2,3,4)

+

Example:

+
DFN.params['edistr']['value'] = [1, 2, 4]
+# Fracture Family 1 will use a LogNormal Distribution
+# Fracture Family 2 will use a Truncated powerlaw distribution
+# Fracture Family 3 will have a constant sized fractures
+
+
+
+

Note

+

Number of elements in the parameters for each distribution must match number of families assigned to that distribution.

+
+
+
+

Ellipse: Lognormal Distribution

+

Fracture radii are sampled from a Lognormal distribution with the following probability density function

+
+

\frac{1}{x \sigma \sqrt{2\pi}} \exp \left (- \frac{(\ln x -\mu)^2}{2 \sigma^2} \right)

+

with mean \mu and variance \sigma^2.

+
+

Warning

+

dfnGen uses the mean and standard deviation of the underlying normal distribution that creates the lognormal distribution not the mean and variance of the lognormal distribution.

+
+

In order to produce a LogNormal distribution with a desired mean (\mu) and variance (\sigma^2) one uses

+
+

eLogMean = \ln  \left ( \frac{\mu^2}{\sqrt{\mu^2 + \sigma^2}} \right)

+

and

+
+

esd =  \sqrt{\ln \left ( 1 + \frac{ \sigma^2}{\mu^2} \right )}

+

For more details see https://en.wikipedia.org/wiki/Log-normal_distribution.

+
+
+
eLogMean
+
+

Warning

+

This value is not the mean of the Log Normal distribution. Use the equations above to convert between the values if needed.

+
+

Description: Mean value of the underlying normal distribution

+

Type: list of float. Length is the number of elements in edistr set to 1.

+

Example:

+
DFN.params['eLogMean']['value'] = [1.609] # This value along with that in esd produce a lognormal with mean 5 m and variance of 0.1
+
+
+
+
+
+
esd
+
+

Warning

+

This value is not the standard deviation of the Log Normal distribution. Use the equations above to convert between the values if needed.

+
+

Description: Standard deviation value of the underlying normal distribution

+

Type: list of Positive floats. Length is the number of elements in edistr set to 1.

+

Example:

+
DFN.params['esd']['value'] = [0.040] # This value along with that in eLogMean produce a lognormal with mean 5 m and variance of 0.1
+
+
+
+
+
+
eLogMin
+

Description: Minimum radius created by the LogNormal distribution for each family

+

Type: list of Positive floats. Length is the number of elements in edistr set to 1.

+

Example:

+
DFN.params['eLogMin']['value'] = [1,0.4]
+# Lognormal family 1 has a minimum radius of 1 m
+# Lognormal family 2 has a maximum radius of 0.4 m
+
+
+
+

Note

+

eLogMin must be less than eLogMax within each family.

+
+
+
+
eLogMax
+

Description: Maximum radius created by the LogNormal distribution for each family

+

Type: list of Positive floats. Length is the number of elements in edistr set to 1.

+

Example:

+
DFN.params['eLogMax']['value'] = [10,12]
+# Lognormal family 1 has a maximum radius of 10 m
+# Lognormal family 2 has a maximum radius of 12 m
+
+
+
+

Note

+

eLogMax must be greater than eLogMin within each family.

+
+
+
+
+
+

Ellipse: Truncated Powerlaw Distribution

+

Fracture radii are sampled from a truncated power-law distribution with lower bound r_0, upper bound r_u, and exponent \alpha defined by the following probability density function

+
+

\frac{\alpha}{r_0} \frac{(r/r_0)^{-1-\alpha}}{1 - (r_u/r_0)^{-\alpha}}.

+

+
+
ealpha
+

Description: Exponent of the truncated powerlaw distribution

+

Type: list of Positive floats. Length is the number of elements in edistr set to 2.

+

Example:

+
DFN.params['ealpha']['value'] = [1.6, 2.2]
+# TPL family 1 has an alpha of 1.6
+# TPL family 2 has an alpha of 2.2
+
+
+
+

Note

+

A value of 0 creates constant sized fractures of size emin

+
+
+
+
+
emin
+

Description: Lower cutoff of the truncated powerlaw distribution

+

Type: list of Positive floats. Length is the number of elements in edistr set to 2.

+

Example:

+
DFN.params['emin']['value'] = [1.2, 5]
+# TPL family 1 has an lower cutoff of 1.2 m
+# TPL family 2 has an lower cutoff of 5 m
+
+
+
+

Note

+

emin must be less than emax within each family.

+
+
+
+
+
emax
+

Description: Upper cutoff of the truncated powerlaw distribution

+

Type: list of Positive floats. Length is the number of elements in edistr set to 2.

+

Example:

+
DFN.params['emax']['value'] = [10, 50]
+# TPL family 1 has an upper cutoff of 10 m
+# TPL family 2 has an upper cutoff of 50 m
+
+
+
+

Note

+

emax must be greater than emin within each family.

+
+
+
+
+
+

Ellipse: Exponential Distribution

+

Fracture radii are sampled from a exponential distribution with the following probability density function

+
+

\lambda e^{-\lambda x}

+

Where \lambda is referred to as the rate parameter.

+
+
+
eExpMean
+

Description: Mean value of each exponential distribution

+

Type: list of Positive floats. Length is the number of elements in edistr set to 3.

+

Example:

+
DFN.params['eExpMean']['value'] = [10, 25]
+# Exponential family 1 has a mean value of 10 m
+# Exponential family 2 has a mean value of 25 m
+
+
+
+

Note

+

eExpMean equal to 1/\lambda where \lambda is the rate parameter of the distribution.

+
+
+
+
+
eExpMin
+

Description: Lower cutoff of the exponential distribution families

+

Type: list of Positive floats. Length is the number of elements in edistr set to 3.

+

Example:

+
DFN.params['eExpMin']['value'] = [1, 7]
+# Exponential family 1 has a lower cutoff value of 1 m
+# Exponential family 2 has a lower cutoff value of 7 m
+
+
+
+

Note

+

eExpMin must be less than eExpMax within each family.

+
+
+
+
+
eExpMax
+

Description: Upper cutoff of the exponential distribution families

+

Type: list of Positive floats. Length is the number of elements in edistr set to 3.

+

Example:

+
DFN.params['eExpMax']['value'] = [527, 89]
+# Exponential family 1 has a upper cutoff value of 527 m
+# Exponential family 2 has a upper cutoff value of 89 m
+
+
+
+

Note

+

eExpMax must be greater than eExpMin within each family.

+
+
+
+
+
+

Ellipse: Constant

+

Constant sized fracture families are defined using a single parameter econst. These families are also referred to as uniform or mono-disperse.

+
+
+
econst
+

Description: Constant radius for each family

+

Type: list of Positive floats. Length is the number of elements in edistr set to 4.

+

Example:

+
DFN.params['econst']['value'] = [1, 7]
+# Constant family 1 has a x-radius of 1 m
+# Constant family 2 has a x-radius of 7 m
+
+
+
+
+
+
+
+
+

Fracture Family Generation Parameters: Rectangle

+

This section describes generation parameters for families of rectangular fractures. The number of elements in each parameter matches the number of rectangle families in nFamRect. The index of the elements corresponds to the fracture family. The first element of each parameter corresponds to the first family, the second element corresponds to the second family, etc.

+
+

Warning

+

The parameters shown in this section are automatically written to the parameter dictionary (DFN.params) when defining fracture families. Documentation here is meant to provide additional information on the definition of each parameter in the parameter dictionary. For information on setting these parameters see pydfnGen

+
+
+

Rectangle: General Parameters

+
+

nFamRect

+

Description: Number of rectangle families

+

Type: Non-Negative Integer

+

Default: 0

+

Example:

+
DFN.params['nFamRect']['value'] = 3 # There will be 3 rectangle families
+
+
+
+
+
+

rLayer

+

Description: Assign each rectangle family to a layer in domain.

+

Type: list of nFamRect integers

+

Example:

+
DFN.params['rLayer']['value'] = [0,2,1]
+# Family 1 is assigned to the whole domain
+# Family 2 is assigned to layer 2
+# Family 3 is assigned to layer 1
+
+
+
+

Note

+

Layer 0 is the entire domain. Numbers > 0 correspond to those defined in layers.

+
+
+

Warning

+

Families can only be assigned to either a layer or a region, not both.

+
+
+
+
+

rRegion

+

Description: Assign each rectangle family to a region in domain.

+

Type: list of nFamRect integers

+

Example:

+
DFN.params['rRegion']['value'] = [0,2,1]
+# Family 1 is assigned to the whole domain
+# Family 2 is assigned to region 2
+# Family 3 is assigned to region 1
+
+
+
+

Note

+

Region 0 is the entire domain. Numbers > 0 correspond to those defined in regions.

+
+
+

Warning

+

Families can only be assigned to either a layer or a region, not both.

+
+
+
+
+

r_p32Targets

+

Description: Target fracture intensity per family. Fracture intensity P_{32} [\text{m}^{-1}] is defined as total surface area of each fracture family divided by the total domain volume. Fractures from each family are inserted into the domain until provided target values are obtained. Generation stops once all desired fracture intensity are obtained.

+

Type: list of nFamRect floats

+

Example:

+
DFN.params['r_p32Targets']['value'] = [0.02,0.4,0.05]
+# Family 1 has a target p32 of 0.02
+# Family 2 has a target p32 of 0.4
+# Family 3 has a target p32 of 0.05
+
+
+
+

Note

+

Only used when stopCondition = 1

+
+
+

Warning

+

The fracture surface area is defined using both sides of a fracture.

+
+
+
+
+

raspect

+

Description: Aspect ratio of fractures

+

Type: list of nFamRect floats

+

Example:

+
DFN.params['raspect']['value'] = [1,2,0.5]
+# Family 1 has an aspect ratio of 1 (circles)
+# Family 2 has an aspect ratio of 2 - y radius is twice the x radius
+# Family 3 has an aspect ratio of 0.5 - y radius is 1/2 the x radius
+
+
+
+

Note

+

A value of 1 makes squares

+
+
+
+
+
+

Rectangle: Fracture Orientation

+

The fracture orientations are sampled from the three-dimensional von Mises-Fisher distribution,

+
+

f({\bf x}; {\boldsymbol \mu}, \kappa ) = \frac{ \kappa \exp( \kappa {\boldsymbol \mu}^{T} {\bf x} )}{ 4 \pi \sinh(\kappa)}~.

+

where {\boldsymbol \mu} is the mean orientation vector and T denotes transpose. +The distribution is sampled using the algorithm provided Simulation of the von Mises Fisher distribution Communications in statistics-simulation and computation 23.1 (1994): 157-164. by Andrew Wood..

+

dfnGen accepts spherical coordinates (\theta/\phi), Trend/Plunge, or Dip/Strike to define the mean orientation of a fracture family.

+
+

Tip

+

orientationOption indicates which of these options are used. This is automatically set based on which option is used during fracture family parameter generation. The same option must be used for all families.

+
+
0 : Spherical Coordinate (Theta/Phi)
+
1 : Trend / Plunge
+
2 : Dip / Strike.
+
+
+
+
+

rkappa

+

Description: The concentration parameter of the von Mises-Fisher distribution, which determines the degree of clustering around the mean orientation.

+

Type: list of nFamRect floats

+

Example:

+
DFN.params['rkappa']['value'] = [0.1, 20, 17]
+# Fracture Family 1 has a theta value of 45 degrees
+# Fracture Family 2 has a theta value of 78 degrees
+# Fracture Family 3 has a theta value of 0 degrees
+
+
+
+

Note

+

Values of \kappa approaching zero result in a uniform distribution of points on the sphere. Larger values create points with a small deviation from mean direction.

+
+
+

Warning

+

The numerical method for sampling the von Mises-Fisher distribution becomes unstable for values greater than 100.

+
+
+
+
+

Rectangle: Spherical Coordinates

+

The mean normal vector of the fracture family \vec{n} is related to the spherical coordinates \theta and \phi by

+
+

\vec{n}_x & = \sin(\theta) \cos(\phi)\\

+
+

\vec{n}_y & = \sin(\theta) \sin(\phi)\\

+
+

\vec{n}_z & = \cos(\theta)

+
+
rtheta
+

Description: Angle the normal vector of the fracture makes with the z-axis

+

Type: list of nFamRect floats

+

Example:

+
DFN.params['rtheta']['value'] = [45, 78, 0]
+# Fracture Family 1 has a theta value of 45 degrees
+# Fracture Family 2 has a theta value of 78 degrees
+# Fracture Family 3 has a theta value of 0 degrees
+
+
+
+

Note

+

Both radians and degrees are supported. Use angleOption to select one. If angleOption is set to radians angleOption = ‘radian’, and the value provided must be less than 2 \pi.

+
+
+
+
+
rphi
+

Description: Angle that the projection of the normal vector of a fracture onto the x-y plane makes with the x-axis.

+

Type: list of nFamRect float

+

Example:

+
DFN.params['rphi']['value'] =  [0, 56, 12]
+# Fracture Family 1 has a phi value of 0 degrees
+# Fracture Family 2 has a phi value of 56 degrees
+# Fracture Family 3 has a phi value of 12 degrees
+
+
+
+

Note

+

Both radians and degrees are supported. Use angleOption to select one. If angleOption is set to radians angleOption = ‘radian’, then the value provided must be less than 2 \pi.

+
+
+
+
+
+

Rectangle: Trend & Plunge

+

The mean normal vector of the fracture family \vec{n} is related to trend and plunge by

+
+

\vec{n}_x & = \cos(\text{trend}) \cos(\text{plunge})\\

+
+

\vec{n}_y & = \sin(\text{trend}) \cos(\text{plunge})\\

+
+

\vec{n}_z & = \sin(\text{trend})

+
+
rtrend
+

Description: Trend of fracture families

+

Type: list of nFamRect float

+

Example

+
DFN.params['rtrend']['value'] = [0, 56, 12]
+# Fracture Family 1 has a trend value of 0 degrees
+# Fracture Family 2 has a trend value of 56 degrees
+# Fracture Family 3 has a trend value of 12 degrees
+
+
+
+

Note

+

angleOption must be set to degree (angleOption = ‘degree’) to use Trend & Plunge

+
+
+
+
+
rplunge
+

Description: Plunge of fracture families

+

Type: list of nFamRect float

+

Example

+
DFN.params['rplunge']['value'] = [0, 56, 12]
+# Fracture Family 1 has a plunge value of 0 degrees
+# Fracture Family 2 has a plunge value of 56 degrees
+# Fracture Family 3 has a plunge value of 12 degrees
+
+
+
+

Note

+

angleOption must be set to degree (angleOption = ‘degree’) to use Trend & Plunge

+
+
+
+
+
+

Rectangle: Dip & Strike

+

The mean normal vector of the fracture family \vec{n} is related to dip and strike by

+
+

\vec{n}_x & = \sin(\text{dip}) \sin(\text{strike})\\

+
+

\vec{n}_y & = -\sin(\text{dip}) \cos(\text{strike})\\

+
+

\vec{n}_z & = \cos(\text{dip})

+

+
+
rstrike
+

Description: Strike of fracture families

+

Type: list of nFamRect float

+

Example

+
DFN.params['rstrike']['value'] = [0, 56, 12]
+# Fracture Family 1 has a strike value of 0 degrees
+# Fracture Family 2 has a strike value of 56 degrees
+# Fracture Family 3 has a strike value of 12 degrees
+
+
+
+

Note

+

angleOption must be set to degree (angleOption = ‘degree’) to use Dip & Strike

+
+
+
+
+
rdip
+

Description: Dip of fracture families

+

Type: list of nFamRect float

+

Example

+
DFN.params['rdip']['value'] = [0, 56, 12]
+# Fracture Family 1 has a dip value of 0 degrees
+# Fracture Family 2 has a dip value of 56 degrees
+# Fracture Family 3 has a dip value of 12 degrees
+
+
+
+

Note

+

angleOption must be set to degree (angleOption = ‘degree’) to use Dip & Strike

+
+
+
+
+
+

Rectangle: In Plane Rotation

+
+
rbetaDistribution
+

Description: Prescribe a rotation around each fracture’s normal vector, with the fracture centered on x-y plane at the origin

+

Type: list of nFamRect boolean values

+
+
0: Uniform distribution on [0, 2 \pi )
+
1: Constant rotation specified by rbeta
+
+
DFN.params['rbetaDistribution']['value'] = [0, 1, 1]
+# Fracture Family 1 will have a random rotation
+# Fracture Family 2 will have a constant angle of rotation defined in the first entry of ebeta
+# Fracture Family 3 will have a constant angle of rotation defined in the second entry of ebeta
+
+
+
+
+
+
rbeta
+

Description: Values for constant angle of rotation around the normal vector

+

Type: list of boolean (0/1)

+

Example:

+
DFN.params['rbetaDistribution']['value'] = [45, 270] # For ebetaDistribution: [0, 1, 1]
+# Fracture Family 2 will have a constant angle of rotation of 45 degrees
+# Fracture Family 3 will have a constant angle of rotation of 270 degrees
+
+
+
+

Note

+
+
1. The length of rbeta corresponds to the number of non-zero entries in rbetaDistribution
+
2. :ref: angleOption defines if the values are in radians or degrees
+
+
+
+
+
+
+

Rectangle: Fracture Radius Distributions

+

Fracture radii can be defined using four different distributions: (1) Log-Normal, (2) Truncated Power-law, (3) Exponential, and (4) Constant. Minimum and maximum values must be provided for 1-3 along with the distribution parameters.

+
+
+

rdistr

+

Description: Assigns fracture radius distribution for each family

+

Type: list of nFamRect Integers (1,2,3,4)

+

Example:

+
DFN.params['rdistr']['value'] = [1, 2, 4]
+# Fracture Family 1 will use a LogNormal Distribution
+# Fracture Family 2 will use a Truncated powerlaw distribution
+# Fracture Family 3 will have a constant sized fractures
+
+
+
+

Note

+

Number of elements in the parameters for each distribution must match number of families assigned to that distribution.

+
+
+
+

Rectangle: Lognormal Distribution

+

Fracture radii are sampled from a Lognormal distribution with the following probability density function

+
+

\frac{1}{x \sigma \sqrt{2\pi}} \exp \left (- \frac{(\ln x -\mu)^2}{2 \sigma^2} \right)

+

with mean \mu and variance \sigma^2.

+
+

Warning

+

dfnGen uses the mean and standard deviation of the underlying normal distribution that creates the lognormal distribution not the mean and variance of the lognormal distribution.

+
+

In order to produce a LogNormal distribution with a desired mean (\mu) and variance (\sigma^2) one uses

+
+

eLogMean = \ln  \left ( \frac{\mu^2}{\sqrt{\mu^2 + \sigma^2}} \right)

+

and

+
+

esd =  \sqrt{\ln \left ( 1 + \frac{ \sigma^2}{\mu^2} \right )}

+

For more details see https://en.wikipedia.org/wiki/Log-normal_distribution.

+
+
+
rLogMean
+
+

Warning

+

This value is not the mean of the Log Normal distribution. Use the equations above to convert between the values if needed.

+
+

Description: Mean value of the underlying normal distribution

+

Type: list of float. Length is the number of elements in rdistr set to 1.

+

Example:

+
DFN.params['rLogMean']['value'] = [1.609] # This value along with that in esd produce a lognormal with mean 5 m and variance of 0.1
+
+
+
+
+
+
rsd
+
+

Warning

+

This value is not the standard deviation of the Log Normal distribution. Use the equations above to convert between the values if needed.

+
+

Description: Standard deviation value of the underlying normal distribution

+

Type: list of Positive floats. Length is the number of elements in rdistr set to 1.

+

Example:

+
DFN.params['rsd']['value'] = [0.040] # This value along with that in rLogMean produce a lognormal with mean 5 m and variance of 0.1
+
+
+
+
+
+
rLogMin
+

Description: Minimum radius created by the LogNormal distribution for each family

+

Type: list of Positive floats. Length is the number of elements in rdistr set to 1.

+

Example:

+
DFN.params['rLogMin']['value'] = [1,0.4]
+# Lognormal family 1 has a minimum radius of 1 m
+# Lognormal family 2 has a maximum radius of 0.4 m
+
+
+
+

Note

+

rLogMin must be less than rLogMax within each family.

+
+
+
+
rLogMax
+

Description: Maximum radius created by the LogNormal distribution for each family

+

Type: list of Positive floats. Length is the number of elements in rdistr set to 1.

+

Example:

+
DFN.params['rLogMax']['value'] = [10,12]
+# Lognormal family 1 has a maximum radius of 10 m
+# Lognormal family 2 has a maximum radius of 12 m
+
+
+
+

Note

+

rLogMax must be greater than rLogMin within each family.

+
+
+
+
+
+

Rectangle: Truncated Powerlaw Distribution

+

Fracture radii are sampled from a truncated power-law distribution with lower bound r_0, upper bound r_u, and exponent \alpha defined by the following probability density function

+
+

\frac{\alpha}{r_0} \frac{(r/r_0)^{-1-\alpha}}{1 - (r_u/r_0)^{-\alpha}}.

+

+
+
ralpha
+

Description: Exponent of the truncated powerlaw distribution

+

Type: list of Positive floats. Length is the number of elements in rdistr set to 2.

+

Example:

+
DFN.params['ralpha']['value'] = [1.6, 2.2]
+# TPL family 1 has an alpha of 1.6
+# TPL family 2 has an alpha of 2.2
+
+
+
+

Note

+

A value of 0 creates constant sized fractures of size rmin

+
+
+
+
+
rmin
+

Description: Lower cutoff of the truncated powerlaw distribution

+

Type: list of Positive floats. Length is the number of elements in rdistr set to 2.

+

Example:

+
DFN.params['rmin']['value'] = [1.2, 5]
+# TPL family 1 has an lower cutoff of 1.2 m
+# TPL family 2 has an lower cutoff of 5 m
+
+
+
+

Note

+

rmin must be less than rmax within each family.

+
+
+
+
+
rmax
+

Description: Upper cutoff of the truncated powerlaw distribution

+

Type: list of Positive floats. Length is the number of elements in rdistr set to 2.

+

Example:

+
DFN.params['rmax']['value'] = [10, 50]
+# TPL family 1 has an upper cutoff of 10 m
+# TPL family 2 has an upper cutoff of 50 m
+
+
+
+

Note

+

rmax must be greater than rmin within each family.

+
+
+
+
+
+

Rectangle: Exponential Distribution

+

Fracture radii are sampled from a exponential distribution with the following probability density function

+
+

\lambda e^{-\lambda x}

+

Where \lambda is referred to as the rate parameter.

+
+
+
rExpMean
+

Description: Mean value of each exponential distribution

+

Type: list of Positive floats. Length is the number of elements in rdistr set to 3.

+

Example:

+
DFN.params['rExpMean']['value'] = [10, 25]
+# Exponential family 1 has a mean value of 10 m
+# Exponential family 2 has a mean value of 25 m
+
+
+
+

Note

+

rExpMean equal to 1/\lambda where \lambda is the rate parameter of the distribution.

+
+
+
+
+
rExpMin
+

Description: Lower cutoff of the exponential distribution families

+

Type: list of Positive floats. Length is the number of elements in rdistr set to 3.

+

Example:

+
DFN.params['rExpMin']['value'] = [1, 7]
+# Exponential family 1 has a lower cutoff value of 1 m
+# Exponential family 2 has a lower cutoff value of 7 m
+
+
+
+

Note

+

rExpMin must be less than rExpMax within each family.

+
+
+
+
+
rExpMax
+

Description: Upper cutoff of the exponential distribution families

+

Type: list of Positive floats. Length is the number of elements in rdistr set to 3.

+

Example:

+
DFN.params['rExpMax']['value'] = [527, 89]
+# Exponential family 1 has a upper cutoff value of 527 m
+# Exponential family 2 has a upper cutoff value of 89 m
+
+
+
+

Note

+

rExpMax must be greater than rExpMin within each family.

+
+
+
+
+
+

Rectangle: Constant

+

Constant sized fracture families are defined using a single parameter rconst. These families are also referred to as uniform or mono-disperse.

+
+
+
rconst
+

Description: Constant radius for each family

+

Type: list of Positive floats. Length is the number of elements in rdistr set to 4.

+

Example:

+
DFN.params['rconst']['value'] = [1, 7]
+# Constant family 1 has a x-radius of 1 m
+# Constant family 2 has a x-radius of 7 m
+
+
+
+
+
+
+
+
+

User Defined Fracture Generation Parameters

+

User defined deterministic features can be included into dfnWorks in a number of ways. There are two format options for ellipses and rectangles. One can also put in a selection of convex n vertex polygons.

+
+

Note

+

To incoperate user fractures into the domain see functions add_user_fract and add_user_fract_from_file in pydfnGen. Information in this section provides additional information about parameters as well as information for adding user fractures from a predefined file.

+
+
+

User Defined Ellipses

+

Ellipses can be included using two different formats: general or coordinates.

+
+

userEllipsesOnOff

+

Description: Selection if general user defined ellipses are going to be used. If this option is activated, then the file UserEll_Input_File_Path is read. The path to that file must be valid.

+

Type: boolean (0/1)

+
+
0: Do not include general user defined ellipses
+
1: Do include general user defined ellipses
+
+
+
+
+

UserEll_Input_File_Path

+

Description: Filepath for general user defined ellipses.

+

Type: string

+

Example:

+
DFN.params['UserEll_Input_Filepath']['value'] = '/dfnWorks/examples/4_user_ell_uniform/define_4_user_ellipses.dat'
+
+
+
+
+
+

General user defined ellipses parameters

+

Below are the required parameters for the general user defined ellipses

+
+
nUserEll
+

Description: Number of User Defined Ellipses

+

Type: Int

+

Example:

+
nUserEll: 2 // 2 ellipses are expected in the file
+
+
+
+
+
+
Number_of_Vertices
+

Description: Number of vertices defining the boundary of each ellipse. One per line per fracture.

+

Type: Int

+

Example:

+
Number_of_Vertices:
+12 // fracture 1 has 12 vertices
+8 // fracture 2 has 8 vertices
+
+
+
+
+
+
Radii
+

Description: Radius of each ellipse

+

Type: Double, one value per line per fracture

+

Example:

+
Radii:
+0.5 // fracture 1 has a radius of 0.5 m
+1 // fracture 1 has a radius of 1 m
+
+
+
+
+
+
Aspect_Ratio
+

Description: Aspect Ratio for each ellipse

+

Type: Double, one value per line per fracture

+

Example:

+
Aspect_Ratio:
+1 // fracture 1 has a radius of 1
+2 // fracture 2 has a radius of 2
+
+
+
+
+
+
AngleOption (User Defined Fracture)
+

Description: Selection of Radius / Degrees

+

Type: boolean

+
+
0: All angles in radians
+
1: All angles in degrees
+
+

Example:

+
AngleOption:
+0 // fracture 1 has angles in radians
+1 // fracture 2 has angles in degrees
+
+
+
+
+
+
Beta
+

Description: Rotation around center for each ellipse (one per line)

+

Type: Double, one value per line per fracture

+

Example:

+
AngleOption:
+0 // no rotation for fracture 1
+45 // rotate fracture 2 by 45 degrees
+
+
+
+
+
+
Translation
+

Description: Translation of each ellipse according to its center {x,y,z} (one per line)

+

Type: Set of double values {x,y,z}

+

Example:

+
Translation:
+{-0.2,0,0} // Fracture 1 has a center at -0.2, 0, 0
+{0,1,0} // Fracture 2 has a center at 0, 1, 0
+
+
+
+
+
+
userOrientationOption
+

Description: Selection of fracture orientation definition. The same orientation option must be used for all fractures.

+
+
+
0 : Normal Vector -> Normal {x,y,z}
+
1 : Trend / Plunge
+
2 : Dip / Strike
+
+
+

Type: Value of 0,1,2

+

Example:

+
userOrientationOption: 0 // Fracture orientation will be defined using normal vectors
+
+
+
+

Note

+
+
If option 0 is selected, the keyword normal is required.
+
If option 1 is selected, the keyword Trend_Plunge is required.
+
If option 2 is selected, the keyword Dip_Strike is required.
+
+
+
+

Warning

+

You cannot mix orientation options

+
+
+
+
+
Normal
+

Description: Normal vector of each ellipse according {x,y,z} (one per line)

+

Type: Set of double values {x,y,z}

+

Example:

+
Normal:
+{0,0,1} // Fracture 1 has a normal vector of [0,0,1]
+{1,1,0} // Fracture 1 has a normal vector of [1,1,0]
+
+
+
+

Note

+

Vectors do not need to be normalized

+
+
+
+
+
Trend_Plunge
+

Description: Trend and plunge for each fracture

+

Type: Set of double values {trend,plunge}

+

Example:

+
Trend_Plunge:
+{45, 90} // Fracture 1 has a trend of 45 and plunge of 90
+{0, 37} // Fracture 2 has a trend of 0 and plunge of 37
+
+
+
+

Warning

+

AngleOption (User Defined Fracture) must be set to degrees

+
+
+
+
+
Dip_Strike
+

Description: Dip and Strike for each fracture

+

Type: Set of double values {dip,strike}

+

Example:

+
Trend_Plunge:
+{45, 90} // Fracture 1 has a dip of 45 and strike of 90
+{0, 37} // Fracture 2 has a dip of 0 and strike of 37
+
+
+
+

Warning

+

AngleOption (User Defined Fracture) must be set to degrees

+
+
+
+
+
General Ellipse Input Example
+
/************************* USER DEFINED ELLIPSES ***************************/
+/*****************************************************************************/
+
+/*****************************************************************************/
+//Number of User Defined Ellipses
+/*****************************************************************************/
+nUserEll: 4
+
+
+/*****************************************************************************/
+//Radius for each ellipse (one per line)
+/*****************************************************************************/
+Radii:
+0.5
+0.5
+0.4
+0.4
+
+
+/*****************************************************************************/
+//Aspect Ratio for each ellipse (one per line)
+/*****************************************************************************/
+Aspect_Ratio:
+1
+1
+1
+1
+
+
+/*****************************************************************************/
+//Angle Option: 0 - All angles in radians
+//              1 - All angles in degrees
+/*****************************************************************************/
+AngleOption:
+1
+1
+1
+1
+
+/*****************************************************************************/
+//Rotation around center for each ellipse (one per line)
+/*****************************************************************************/
+Beta:
+0
+0
+0
+0
+
+/*****************************************************************************/
+//Translation of each ellipse according to its center {x,y,z} (one per line)
+/*****************************************************************************/
+Translation:
+{-0.2,0,0}
+{0,0,0}
+{0.2,0,0.2}
+{0.2,0,-0.2}
+
+
+/*****************************************************************************/
+//  userOrientationOption:
+//  0 - Normal Vector -> Normal {x,y,z}
+//  1 - Trend / Plunge -> Trend_Plunge {trend, plunge} -> Must be degrees
+//  2 - Dip / Strike - > Dip_Strike {dip, strike} -> Must be degrees
+/*****************************************************************************/
+
+userOrientationOption: 0
+
+
+/*****************************************************************************/
+//Normal Vector for each ellipse (one per line)
+/*****************************************************************************/
+Normal:
+{0,0,1}
+{1,0,0}
+{0,0,1}
+{0,0,1}
+
+
+Number_of_Vertices:
+8
+8
+8
+8
+
+
+
+
+
+
+

userEllByCoord

+

Description: Selection if user defined ellipses by coordinate are going to be used. If this option is activated, then the file EllByCoord_Input_File_Path is read. The path to that file must be valid.

+

Type: boolean (0/1)

+
+
0: Do not include user defined ellipses by coordinate
+
1: Include user defined ellipses by coordinate
+
+
+

Warning

+

The same number of vertices must be used for all fractures.

+
+
+
+
+

EllByCoord_Input_File_Path

+

Description: File path name for user defined ellipses by coordinate

+

Type: string

+

Example:

+
DFN.params['EllByCoord_Input_File_Path']['value'] = '/dfnWorks/example/4_user_ell/ellCoords.dat'
+
+
+
+
+
+

User defined ellipses by coordinate parameters

+

Below are the required parameters for the user defined ellipses by coordinate

+
+
+
nEllipses
+

Description: Number of User Defined Ellipses

+

Type: Integer

+

Example:

+
nEllipses: 2
+
+
+
+
+
+
nNodes
+

Description: Number of nodes for all ellipses

+

Type: Integer

+
nNodes: 5
+
+
+
+
+
+
Coordinates
+

Description: Coordinates / Vertices for each ellipse.

+

Type: Set of nNodes triples {x_0, y_0, z_0} {x_1, y_1, z_1} \ldots {x_n, y_n, z_n}

+
Coordinates:
+{-2,-1,0} {1,-2,0} {2,0,0} {0,2,0} {-2,1,0}
+{0,-0.3,-1} {0,.5,-.7} {0,.7,1} {0,-.7,1} {0,-1,0}
+
+
+
+

Warning

+

Coordinates must be listed in clockwise, or counterclockwise order. Coordinates must be co-planar

+
+
+
+
+
Ellipse By Coordinate Example
+
/************************************************************************/
+/*                 ELLIPSES SPECIFIED BY COORDINATES                  */
+/************************************************************************/
+// NOTE: Coordinates must be listed in clockwise, or counterclockwise order
+//       Coordinates must be co-planar
+
+/************************************************************************/
+// Number of Ellipses Defined
+/************************************************************************/
+
+nEllipses: 2
+
+
+/************************************************************************/
+// Number of nodes for all ellipses
+/************************************************************************/
+
+nNodes: 5
+
+
+/************************************************************************/
+// Coordinates (4 vertice coordinates per line/One rectangle per line)
+/************************************************************************/
+// One Ellipse per line (White space and new lines should not matter)
+// Format: {x1,y1,z1} {x2,y2,z2} {x3,y3,z3} {x4,y4,z4} ... {xn, yn, zn}
+
+Coordinates:
+
+{-2,-1,0} {1,-2,0} {2,0,0} {0,2,0} {-2,1,0}
+{0,-0.3,-1} {0,.5,-.7} {0,.7,1} {0,-.7,1} {0,-1,0}
+
+
+
+
+
+
+

User Defined Rectangles

+

Deterministic Rectangles can be included using two different formats: general or coordinates.

+
+

userRectanglesOnOff

+

Description: Selection if general user defined rectangles are going to be used. If this option is activated, then the file UserRect_Input_File_Path is read. The path to that file must be valid.

+

Type: boolean (0/1)

+
+
0: Do not include general user defined rectangles
+
1: Do include general user defined rectangles
+
+
+
+
+

UserRect_Input_File_Path

+

Description: Filepath for general user defined rectangles

+

Type: string

+

Example:

+
DFN.params['UserRect_Input_File_Path']['value'] = '/dfnWorks/examples/4_user_rects/define_4_user_rects.dat'
+
+
+
+
+
+

General user defined rectangles parameters

+

Below are the required parameters for the general user defined rectangles

+
+
+
nUserRect
+

Description: Number of user defined rectangles

+

Type: Int

+

Example:

+
nUserRect: 2 // There will be 2 rectangles expected.
+
+
+
+

Additional parameters have the same definitions as for user defined ellipses:

+ +
+
+
+
General Rectangle Input Example
+
/************************* USER DEFINED rectangles ***************************/
+/*****************************************************************************/
+
+/*****************************************************************************/
+//Number of User Defined rectangles
+/*****************************************************************************/
+nUserRect: 4
+
+
+/*****************************************************************************/
+//Radius for each rectangle (one per line)
+/*****************************************************************************/
+Radii:
+0.5
+0.5
+0.4
+0.4
+
+
+/*****************************************************************************/
+//Aspect Ratio for each rectangle (one per line)
+/*****************************************************************************/
+Aspect_Ratio:
+1
+1
+1
+1
+
+
+/*****************************************************************************/
+//Angle Option: 0 - All angles in radians
+//              1 - All angles in degrees
+/*****************************************************************************/
+AngleOption:
+1
+1
+1
+1
+
+/*****************************************************************************/
+//Rotation around center for each rectangle (one per line)
+/*****************************************************************************/
+Beta:
+0
+0
+0
+0
+
+/*****************************************************************************/
+//Translation of each rectangle according to its center {x,y,z} (one per line)
+/*****************************************************************************/
+Translation:
+{-0.2,0,0}
+{0,0,0}
+{0.2,0,0.2}
+{0.2,0,-0.2}
+
+
+/*****************************************************************************/
+//  userOrientationOption:
+//  0 - Normal Vector -> Normal {x,y,z}
+//  1 - Trend / Plunge -> Trend_Plunge {trend, plunge} -> Must be degrees
+//  2 - Dip / Strike - > Dip_Strike {dip, strike} -> Must be degrees
+/*****************************************************************************/
+
+userOrientationOption: 0
+
+
+/*****************************************************************************/
+//Normal Vector for each rectangle (one per line)
+/*****************************************************************************/
+Normal:
+{0,0,1}
+{1,0,0}
+{0,0,1}
+{0,0,1}
+
+
+
+
+
+

userRecByCoord

+

Description: Selection if user defined rectangles by coordinate are going to be used. If this option is activated, then the file RectByCoord_Input_File_Path is read. The path to that file must be valid.

+

Type: boolean (0/1)

+
+
0: Do not include user defined rectangles by coordinate
+
1: include user defined rectangles by coordinate
+
+
+

Warning

+

The same number of vertices must be used for all fractures.

+
+
+
+
+

RectByCoord_Input_File_Path

+

Description: File path name for user defined rectangles by coordinate

+

Type: string

+

Example:

+
DFN.params['RectByCoord_Input_File_Path']['value'] = '/dfnWorks/example/4_user_rect/rectCoords.dat'
+
+
+
+
+
+

User defined rectangles by coordinate parameters

+

Below are the required parameters for the user defined rectangles by coordinate

+
+
+
nRectangles
+

Description: Number of user defined rectangles

+

Type: Integer

+

Example:

+
nRectangles: 2
+
+
+
+

Fracture coordinates are defined using the same method as for ellipses. See Coordinates.

+
+
+
Rectangle By Coordinate Example
+
/************************************************************************/
+/*                 rectangles SPECIFIED BY COORDINATES                  */
+/************************************************************************/
+// NOTE: Coordinates must be listed in clockwise, or counterclockwise order
+//       Coordinates must be co-planar
+
+/************************************************************************/
+// Number of rectangles Defined
+/************************************************************************/
+
+nRectangles: 2
+
+/************************************************************************/
+// Coordinates (4 vertices coordinates per line/One rectangle per line)
+/************************************************************************/
+// One rectangle per line (White space and new lines should not matter)
+// Format: {x1,y1,z1} {x2,y2,z2} {x3,y3,z3} {x4,y4,z4} ... {xn, yn, zn}
+
+Coordinates:
+
+{-2,-1,0} {1,-2,0} {2,0,0} {0,2,0} {-2,1,0}
+{0,-0.3,-1} {0,.5,-.7} {0,.7,1} {0,-.7,1} {0,-1,0}
+
+
+
+
+
+
+

Polygons

+

An example DFN for this input is found in dfnWorks-main/examples/user_polygons.

+
+
+

userPolygonByCoord

+

Description: Selection if user defined polygons are going to be used. If this option is activated, then the file :refPolygonByCoord_Input_File_Path is read. The path to that file must be valid.

+

Type: boolean (0/1)

+
+
0: Do not include user defined polygons
+
1: Do include user defined polygons
+
+
+

Note

+
+
Each polygon can have a different number of vertices.
+
dfnGen automatically outputs the file polygons.dat which can be read back in using this option to create the same DFN.
+
+
+
+
+
+

PolygonByCoord_Input_File_Path:

+

Description: File path for user defined polygons

+

Type: string

+

Example:

+
DFN.params['UserEll_Input_File_Path']['value'] = '/dfnWorks/examples/user_polygons/polygons.dat'
+
+
+
+
+
+

Polygon file format

+

The first line is a keyword nPolygons, the number of fractures in the file. Then each line after nPolygons is a different fracture. The first entry is an integer with the number of vertices in that fracture. The remaining entries are the vertex coordinates. The coordinate format is {x1,y1,z1} {x2,y2,z2} {x3,y3,z3} {x4,y4,z4} … {xn, yn, zn}

+

General Example:

+
nPolygons: 1
+4 {x1,y1,z1} {x2,y2,z2} {x3,y3,z3} {x4,y4,z4} // fracture 1 has 4 vertices with these coordinates
+
+
+

Example generated by dfnGen:

+
nPolygons: 13
+5 {0.614809755508, -5, 10} {0.215302589745, -5, 5.14052566974} {0.545132019741, -3.76296408041, 5.01135305297} {1.46205561432, -1.11169723114, 7.28911258873} {1.7422671348, -0.903335314403, 10}
+5 {-5, 5, -7.34275683413} {-5, -3.19676496723, -8.52840001844} {-2.54841054822, -3.3215018603, -8.70265907788} {2.28455866847, 0.968743065242, -8.39004354883} {2.5300049043, 5, -7.82257143457}
+7 {0.169537908304, -1.10365780918, 7.89449659536} {3.39229757501, -1.47097810869, 9.7368040684} {5, -0.396173810104, 9.9199696155} {5, 5, 6.76351044547} {0.192549006049, 5, 4.33581920939} {-0.157462422292, 4.76600532497, 4.29594241204} {-1.30082072643, 1.47978607543, 5.64081751301}
+6 {-0.793278268371, 5, 1.81778296407} {-0.561983329033, 3.45819042638, 3.44636375172} {1.4541413343, -3.51825209439, 3.66719739398} {2.0912558548, -5, 2.1739128129} {3.74246641127, -5, -10} {0.809628560699, 5, -10}
+8 {-3.56729801834, -4.10664963232, -7.17895163585} {-2.75834169562, -5, -7.23742727251} {2.80010131269, -5, -7.26666449977} {3.40228077595, -4.45665913893, -7.23685468994} {3.54844410108, -1.5749811435, -7.06272440502} {1.61045433532, 0.565188057474, -6.92263630123} {-1.27643915621, 0.710166484812, -6.89865208954} {-3.42113429321, -1.22497133918, -7.00482133497}
+6 {1.61970921408, 0.322281059007, 8.27249031626} {1.91468659533, -0.549550927249, 10} {2.19700291895, -5, 10} {1.3154355331, -5, 3.64584005023} {1.20544838483, -3.98437001886, 3.31745142962} {1.22589362057, -0.804792681255, 4.91861492809}
+8 {-4.70593999999, -3.29639431251, -7.25224389054} {-3.10094407568, -4.6562865987, -7.03245087974} {-0.992518232701, -4.50612429324, -7.10741842947} {0.384249987443, -2.93387033715, -7.43323157864} {0.222868762162, -0.860529584164, -7.81903344627} {-1.38212753352, 0.499362646346, -8.03882643837} {-3.4905528176, 0.349200223043, -7.9638588789} {-4.8673209588, -1.22305329999, -7.63804581282}
+6 {5, 5, -3.39564264412} {2.56312416852, 5, -4.08462835745} {2.41898893677, 4.65124788861, -4.11909954775} {3.10520773081, 2.8645938936, -3.89290711889} {4.80872562941, 2.11160312936, -3.39770554375} {5, 2.19173173493, -3.34506895229}
+6 {-5, 2.42895858094, 6.20485792137} {-5, -5, 4.85177752427} {-1.81351205493, -5, 4.99702019362} {0.0853427250495, -2.66597219167, 5.50868187563} {-0.289753327606, 0.588931258258, 6.08441961571} {-2.88990150472, 2.64805531643, 6.34094328974}
+8 {-0.922507014307, -1.71519798881, 2.85778630995} {-0.841071899053, 0.310044679731, 1.25820816606} {-1.26426496474, 2.84566856205, 1.49988903618} {-1.94418542615, 4.40633923745, 3.44125563949} {-2.48254521057, 4.07783735953, 5.94508200102} {-2.5639802392, 2.05259419185, 7.54466008318} {-2.14078724661, -0.483028953749, 7.30297907019} {-1.4608669326, -2.04369954706, 5.36161304612}
+8 {2.18143095055, -0.610312831185, -4.21771261931} {2.80909183961, 0.814183043594, -4.47247873318} {2.26469088948, 2.29432736239, -4.44327042469} {0.867130728085, 2.96307141873, -4.14719749191} {-0.564917036364, 2.42867426252, -3.75769541671} {-1.19257780773, 1.00417817281, -3.50292931657} {-0.648176891617, -0.475965761662, -3.53213764385} {0.74938298608, -1.14470985076, -3.82821050463}
+6 {-1.27165416308, 5, 10} {-1.97370232204, 1.13046740212, 10} {-2.01807341608, 0.962283071202, 9.35725325459} {-1.83562647916, 2.23286105726, 7.12746635144} {-1.40616097581, 4.67958113114, 6.45759785589} {-1.34398137987, 5, 6.64526675756}
+
+
+
+
+
nPolygons
+

Description: Number of polgyons/fractures

+

Type: integer

+

Example:

+
nPolygons: 3 // Read in three polygons/fractures
+
+
+
+
+
+
+
+

Source Code Documentation (Doxygen)

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/dfntrans.html b/Documentation/sphinx-docs/build/html/dfntrans.html new file mode 100644 index 000000000..c2320f149 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/dfntrans.html @@ -0,0 +1,162 @@ + + + + + + + dfnTrans — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

dfnTrans

+

dfnTrans is a method for resolving solute transport using control volume flow +solutions obtained from dfnFlow on the unstructured mesh generated using dfnGen. +We adopt a Lagrangian approach and represent a non-reactive conservative solute +as a collection of indivisible passive tracer particles. Particle tracking +methods (a) provide a wealth of information about the local flow field, (b) do +not suffer from numerical dispersion, which is inherent in the discretizations +of advection–dispersion equations, and (c) allow for the computation of each +particle trajectory to be performed in an intrinsically parallel fashion if +particles are not allowed to interact with one another or the fracture network. +However, particle tracking on a DFN poses unique challenges that arise from (a) +the quality of the flow solution, (b) the unstructured mesh representation of +the DFN, and (c) the physical phenomena of interest. The flow solutions obtained +from dfnFlow are locally mass conserving, so the particle tracking method does +not suffer from the problems inherent in using Galerkin finite element codes.

+

dfnTrans starts from reconstruction of local velocity field: Darcy fluxes +obtained using dfnFlow are used to reconstruct the local velocity field, which +is used for particle tracking on the DFN. Then, Lagrangian transport simulation +is used to determine pathlines through the network and simulate transport. It is +important to note that dfnTrans itself only solves for advective transport, but +effects of longitudinal dispersion and matrix diffusion, sorption, and other +retention processes are easily incorporated by post-processing particle +trajectories.

+

The detailed description of dfnTrans algorithm and implemented +methodology is in Makedonska, N., Painter, S. L., Bui, Q. M., Gable, C. W., & +Karra, S. (2015). Particle tracking approach for transport in three-dimensional +discrete fracture networks. Computational Geosciences, 19(5), 1123-1137.

+
+

Documentation

+

Doxygen

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/examples.html b/Documentation/sphinx-docs/build/html/examples.html new file mode 100644 index 000000000..70ee6a791 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/examples.html @@ -0,0 +1,210 @@ + + + + + + + Examples — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Examples

+

This section contains a few examples of DFN generated using dfnWorks. All required input files for these examples are contained in the folder dfnWorks/examples/. The focus of this document is to provide visual confirmation that new users of dfnWorks have the code set up correctly, can carry out the following runs and reproduce the following images. All images are rendered using Paraview, which can be obtained for free at http : //www.paraview.org/. The first two examples are simplest so it is recommended that the user proceed in the order presented here.

+

All examples are in the examples/ directory. Within each subdirectory are the files required to run the example. The command line input is found in notes.txt. Be sure that you have created ~/test_output_files prior to running the examples.

+
+

4_user_defined_rects

+

Location: examples/4_user_defined_rects/

+

This test case consists of four user defined rectangular fractures within a a cubic domain with sides of length one meter. The network of four fractures, each colored by material ID. The computational mesh is overlaid on the fractures. This image is created by loading the file full_mesh.inp. located in the job folder into Paraview.

+
+alternate text + +
+

The meshed network of four rectangular fractures.

+
+
+

High pressure (red) Dirichlet boundary conditions are applied on the edge of the single fracture along the boundary x = -0.5, and low pressure (blue) boundary conditions are applied on the edges of the two fractures at the boundary x = 0.5. +This image is created by loading the file parsed_vtk/dfn_explicit-001.vtk into Paraview.

+

Particles are inserted uniformly along the inlet fracture on the left side of the image. +Particles exit the domain through the two horizontal fractures on the right side of the image. +Due to the stochastic nature of the particle tracking algorithm, your pathlines might not be exactly the same as in this image. +Trajectories are colored by the current velocity magnitude of the particle’s velocity. +Trajectories can be visualized by loading the files part_*.inp, in the folder 4_user_rectangles/traj/trajectories/

+

We have used the extract surface and tube filters in paraview for visual clarity.

+
+
+

4_user_defined_ell_uniform

+

Location: examples/4_user_defined_ell_uniform/

+

This test case consists of four user defined elliptical fractures within a a cubic domain with sides of length one meter. In this case the ellipses are approximated using 8 vertices. We have set the meshing resolution to be uniform by including the argument slope=0 into the mesh_networks function in run_explicit.py.

+
+alternate text + +
+

The uniformly meshed network of four circular fractures.

+
+
+
+
+

exp: Exponentially Distributed fracture lengths

+

Location: examples/exp/

+

This test case consists of a family of fractures whose size is exponentially distributed with a minimum size of 1m and a maximum size of 50m. The domain is cubic with an edge length of 10m. All input parameters for the generator can be found in tests/gen_exponential_dist.dat. We have changed the flow direction to be aligned with the y-axis by modifying the PFLOTRAN input card dfn_explicit.in

+
+alternate text + +
+

Pressure solution on with rectangular fractures whose lengths following a exponential distribution. Gradient is aligned with the Y-Axis

+
+
+
+
+

TPL: Truncated Power-Law

+

Location: examples/TPL/

+

This test case consists of two families whose sizes have a truncated power law distribution with a minimum size of 1m and a maximum size of 5m an exponent 2.6. The domain size is cubic with an edge length of 15m.

+
+alternate text + +
+
+
+

Graph-based pruning

+

Location: examples/pruning/

+

This example uses a graph representation of a DFN to isolate the 2-core. The pruned DFN has all dead end fractures of the network are removed. This example has two run_explicit.py scripts. The first creates the original DFN and identifies the 2-core using networkx (https://networkx.github.io/). The second meshes the DFN corresponding to the 2-core of the graph and then runs flow and transport. The 2 core network is in a sub-directory 2-core. The original network has 207 fractures and the 2-core has 79 fractures.

+
+alternate text + +
+

(left) Graph based on DFN topology. Each vertex is a fracture in the network. The inflow boundary is colored blue and the outflow is colored red. (right) 2-Core of the graph to the left.

+
+
+
+alternate text + +
+

(left) Original DFN (right) DFN corresponding to the 2-core of the DFN to the left.

+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/gallery.html b/Documentation/sphinx-docs/build/html/gallery.html new file mode 100644 index 000000000..ffbd18457 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/gallery.html @@ -0,0 +1,163 @@ + + + + + + + dfnWorks Gallery — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ + + + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/genindex.html b/Documentation/sphinx-docs/build/html/genindex.html new file mode 100644 index 000000000..722d14de7 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/genindex.html @@ -0,0 +1,652 @@ + + + + + + Index — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + +

Index

+ +
+ A + | C + | D + | E + | F + | G + | I + | K + | L + | M + | O + | P + | R + | S + | T + | U + | W + | Z + +
+

A

+ + + +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

E

+ + +
+ +

F

+ + + +
    +
  • + false_connections.py + +
  • +
+ +

G

+ + + +
+ +

I

+ + + +
+ +

K

+ + +
+ +

L

+ + + +
+ +

M

+ + +
+ +

O

+ + +
+ +

P

+ + + +
    +
  • + pydfnworks.dfnGen.meshing.dfm.mesh_dfm + +
  • +
  • + pydfnworks.dfnGen.meshing.mapdfn_ecpm.mapdfn_ecpm + +
  • +
  • + pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn + +
  • +
  • + pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn_helper + +
  • +
  • + pydfnworks.dfnGen.meshing.udfm.false_connections + +
  • +
  • + pydfnworks.dfnGen.meshing.udfm.map2continuum + +
  • +
  • + pydfnworks.dfnGen.meshing.udfm.upscale + +
  • +
  • + pydfnworks.dfnGen.well_package.wells + +
  • +
  • + pydfnworks.dfnGraph.dfn2graph + +
  • +
  • + pydfnworks.dfnGraph.graph_flow + +
  • +
  • + pydfnworks.dfnGraph.graph_transport + +
  • +
  • + pydfnworks.dfnGraph.pruning + +
  • +
  • + pydfnworks.dfnTrans.transport + +
  • +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + +
+ +

U

+ + + +
    +
  • + upscale.py + +
  • +
+ +

W

+ + +
+ +

Z

+ + +
+ + + +
+
+
+ +
+ +
+

© Copyright 2020, LANL, LA-UR-17-22216.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/index.html b/Documentation/sphinx-docs/build/html/index_docs.html similarity index 96% rename from docs/index.html rename to Documentation/sphinx-docs/build/html/index_docs.html index 08982c333..8ecc96643 100644 --- a/docs/index.html +++ b/Documentation/sphinx-docs/build/html/index_docs.html @@ -1,24 +1,27 @@ - + - + - Welcome to dfnWorks 2.8 documentation! — dfnWorks 2.7 documentation - - + Welcome to dfnWorks 2.8 documentation! — dfnWorks v2.8 documentation + + + + - - + + - + + @@ -29,12 +32,12 @@ - + dfnWorks
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
@@ -69,17 +72,17 @@

@@ -343,7 +346,9 @@

Welcome to dfnWorks 2.8 documentation! + +


diff --git a/Documentation/sphinx-docs/build/html/intro.html b/Documentation/sphinx-docs/build/html/intro.html new file mode 100644 index 000000000..7cf2da154 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/intro.html @@ -0,0 +1,386 @@ + + + + + + + Welcome To dfnWorks — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Welcome To dfnWorks

+

dfnWorks is a parallelized computational suite to generate three-dimensional +discrete fracture networks (DFN) and simulate flow and transport. Developed at +Los Alamos National Laboratory, it has been used to study flow and transport +in fractured media at scales ranging from millimeters to kilometers. The +networks are created and meshed using dfnGen, which combines FRAM (the feature +rejection algorithm for meshing) methodology to stochastically generate +three-dimensional DFNs with the LaGriT meshing toolbox to create a high-quality +computational mesh representation. The representation produces a conforming +Delaunay triangulation suitable for high-performance computing finite volume +solvers in an intrinsically parallel fashion. Flow through the network is +simulated with dfnFlow, which utilizes the massively parallel subsurface flow +and reactive transport finite volume code PFLOTRAN. A Lagrangian approach to +simulating transport through the DFN is adopted within dfnTrans to determine +pathlines and solute transport through the DFN. Applications of the dfnWorks +suite include nuclear waste repository science, hydraulic fracturing and +CO2 sequestration.

+

To run a workflow using the dfnWorks suite, the pydfnworks package is +highly recommended. pydfnworks calls various tools in the dfnWorks suite with +the aim to provide a seamless workflow for scientific applications of dfnWorks.

+
+

Obtaining dfnWorks

+

dfnWorks can be downloaded from https://github.com/lanl/dfnWorks/

+

A docker container of dfnWorks can be downloaded from https://hub.docker.com/r/ees16/dfnworks

+
+
+

Citing dfnWorks

+

Hyman, J. D., Karra, S., Makedonska, N., Gable, C. W., Painter, S. L., & +Viswanathan, H. S. (2015). dfnWorks: A discrete fracture network framework +for modeling subsurface flow and transport. Computers & Geosciences, 84, +10-19.

+

BibTex:

+
  @article{hyman2015dfnWorks,
+    title={dfnWorks: A discrete fracture network framework
+for modeling subsurface flow and transport},
+    author={Hyman, Jeffrey D and Karra, Satish and Makedonska,
+Nataliia and Gable, Carl W and Painter, Scott L
+and Viswanathan, Hari S},
+    journal={Computers \& Geosciences},
+    volume={84},
+    pages={10--19},
+    year={2015},
+    publisher={Elsevier}
+  }
+
+
+
+
+

Versions

+
+

v2.8 - Current

+
    +
  • New Meshing Using Poisson Disc Sampling (Requires LaGriT v3.3)

  • +
  • Conforming Discrete Fracture Matrix Meshing

  • +
  • ECPM module using MAP DFN

  • +
  • Additional bug fixes

  • +
  • New dfnGraph model capabilities

  • +
  • TDRW matrix diffusion with finite matrix-block size

  • +
+
+
+

v2.7

+
    +
  • Python based assignment of domain parameters, fracture families, user defined fractures

  • +
  • Interactive object interface

  • +
  • Updated for PFLOTRAN 4.0 compatability

  • +
  • Additional bug fixes

  • +
  • Increased detail of warning and errors

  • +
+
+
+

v2.6

+
    +
  • Hydraulic aperture of fracture based on background stress field

  • +
  • Bug fixes

  • +
+
+
+

v2.5

+
    +
  • New Generation parameters, family orientation by trend/plunge and dip/strike

  • +
  • Define fracture families by region

  • +
  • Updated output report

  • +
+
+
+

v2.4

+
    +
  • New meshing technique (Poisson disc sampling)

  • +
  • Define fracture families by region

  • +
  • Updated output report

  • +
  • Well Package

  • +
+
+
+

v2.3

+
    +
  • Bug fixes in LaGrit Meshing

  • +
  • Bug fixes in dfnTrans checking

  • +
  • Bug fixes in dfnTrans output

  • +
  • Expanded examples

  • +
  • Added PDF printing abilities

  • +
+
+
+

v2.2

+
    +
  • pydfnWorks updated for python3

  • +
  • Graph based (pipe-network approximations) for flow and transport

  • +
  • Bug fixes in LaGrit Meshing

  • +
  • Increased functionalities in pydfnworks including the path option

  • +
  • dfn2graph capabilities

  • +
  • FEHM flow solver

  • +
  • Streamline routing option in dfnTrans

  • +
  • Time Domain Random Walk in dfnTrans

  • +
+
+
+

v2.1

+
    +
  • Bug fixes in LaGrit Meshing

  • +
  • Increased functionalities in pydfnworks including the path option

  • +
+
+
+

v2.0

+
    +
  • New dfnGen C++ code which is much faster than the Mathematica dfnGen. This code has successfully generated networks with 350,000+ fractures.

  • +
  • Increased functionality in the pydfnworks package for more streamlined workflow from dfnGen through visualization.

  • +
+
+
+
+

About this manual

+

This manual comprises of information on setting up inputs to dfnGen, dfnTrans +and PFLOTRAN, as well as details on the pydfnworks module: pydfnworks. Finally, the manual contains a short tutorial +with prepared examples that can be found in the examples directory of the +dfnWorks repository, and a description of some applications of the dfnWorks +suite.

+
+
+

Contact

+

Please email dfnworks@lanl.gov with questions about dfnWorks. Please let us know if you publish using dfnWorks and we’ll add it to the Publication Page

+
+
+

Contributors

+
+

LANL

+
    +
  • Jeffrey D. Hyman

  • +
  • Matt Sweeney

  • +
  • Nataliia Makedonska

  • +
  • Carl Gable

  • +
  • Hari Viswanathan

  • +
  • Aric Hagberg

  • +
  • Shriram Srinivasan

  • +
  • Aidan Stansberry

  • +
+
+
+

External

+
    +
  • Satish Karra (PNNL)

  • +
  • Scott Painter (ORNL)

  • +
  • Quan Bui (now at LLNL)

  • +
  • Jeremy Harrod (now at Spectra Logic)

  • +
  • Thomas Sherman (University of Notre Dame)

  • +
  • Johannes Krotz (Oregon State University)

  • +
  • Yu Chen

  • +
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/objects.inv b/Documentation/sphinx-docs/build/html/objects.inv new file mode 100644 index 000000000..eea33c7a7 Binary files /dev/null and b/Documentation/sphinx-docs/build/html/objects.inv differ diff --git a/Documentation/sphinx-docs/build/html/output.html b/Documentation/sphinx-docs/build/html/output.html new file mode 100644 index 000000000..e859d897f --- /dev/null +++ b/Documentation/sphinx-docs/build/html/output.html @@ -0,0 +1,243 @@ + + + + + + + Run Files — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Run Files

+

This section describes the contents and purpose of each file used in dfnWorks and their locations.

+
+

dfnGen - output

+

connectivity.dat:

+

Fracture connection list. Each row corresponds to a single fracture. The integers in that row are the fractures that fracture intersects with. These are the non-zero elements of the adjacency matrix.

+

DFN_output.txt:

+

Detailed information about fracture network. Output by DFNGen.

+

families.dat:

+

Information about fracture families. Produced by DFNGen.

+

input_generator.dat:

+

Input file for DFN generator.

+

input_generator_clean.dat:

+

Abbreviated input file for DFN generator.

+

normal_vectors.dat:

+

Normal vector of each fracture in the network.

+

params.txt:

+

Parameter information about the fracture network used for meshing. Includes number of fractures, h, visualmode, expected number of dudded points, and x,y,z dimensions of the domain.

+

poly_info.dat:

+

Fracture information output by DFNGen. Format: Fracture Number, Family number, rotation angle for rotateln in LaGriT, x0, y0, z0, x1, y1, z1 (end points of line of rotation).

+

user_rects.dat:

+

User defined rectangle file.

+

radii.dat:

+

Concatentate file of fracture radii. Contains fractures that are removed due to isolation.

+

radii_Final.dat:

+

Concatentated file of final radii in the DFN.

+

rejections.dat:

+

Summary of rejection reasons.

+

rejectsPerAttempt.dat:

+

Number of rejections per attempted fracture.

+

translations.dat:

+

Fracture centriods.

+

triple_points.dat:

+

x,y,z location of triple intersection points.

+

warningFileDFNGen.txt:

+

Warning file output by DFNGen.

+

intersection_list.dat:

+

List of intersections between fractures. Format is fracture1 fracture2 x y z length. Negative numbers correspond to intersections with boundaries.

+
+
+

LaGrit - Output

+

bound_zones.lgi:

+

LaGriT run file to identify boundary nodes. Dumps zone files.

+

boundary_output.txt:

+

Output file from bound_zones.lgi.

+

finalmesh.txt:

+

Brief summary of final mesh.

+

full_mesh.inp:

+

Full DFN mesh in AVS format.

+

full_mesh.lg:

+

Full DFN mesh in LaGriT binary format.

+

full_mesh.uge:

+

Full DFN mesh in UGE format. NOTE volumes are not correct in this file. This file is processed by convert_uge to create full_mesh_vol_area.uge, which has the correct volumes.

+

full_mesh_viz.inp:

+

intersections:

+

Directory containing intersection avs files output by the generator and used by LaGrit.

+

lagrit_logs:

+

Directory of output files from individual meshing.

+

logx3dgen:

+

LaGriT output.

+

outx3dgen:

+

LaGriT output.

+

parameters:

+

Directory of parameter*.mgli files used for fracture meshing.

+

polys:

+

Subdirectory contiaining AVS file for polygon boundaries.

+

tri_fracture.stor:

+

FEHM stor file. Information about cell volume and area.

+

user_function.lgi:

+

Function used by LaGriT for meshing. Defines coarsening gradient.

+
+
+

PFLOTRAN - output

+

Fracture based aperture value for the DFN. Used to rescale volumes in full_mesh_vol_area.uge.

+

cellinfo.dat:

+

Mesh information output by PFLOTRAN.

+

dfn_explicit-000.vtk:

+

VTK file of initial conditions of PFLOTRAN. Mesh is not included in this file.

+

dfn_explicit-001.vtk:

+

VTK file of steady-state solution of PFLOTRAN. Mesh is not included in this file.

+

dfn_explicit-mas.dat:

+

pflotran information file.

+

dfn_explicit.in:

+

pflotran input file.

+

_dfn_explicit.out:

+

pflotran output file.

+

dfn_properties.h5:

+

h5 file of fracture network properties, permeability, used by pflotran.

+

Full DFN mesh with limited attributes in AVS format.

+

full_mesh_vol_area.uge:

+

Full DFN in uge format. Volumes and areas have been corrected.

+

materialid.dat:

+

Material ID (Fracture Number) for every node in the mesh.

+

parsed_vtk:

+

Directory of pflotran results.

+

perm.dat:

+

Fracture permeabilities in FEHM format. Each fracture is listed as a zone, starting index at 7.

+

pboundary_back_n.ex:

+

Boundary file for back of the domain used by PFLOTRAN.

+

pboundary_bottom.ex:

+

Boundary file for bottom of the domain used by PFLOTRAN.

+

pboundary_front_s.ex:

+

Boundary file for front of the domain used by PFLOTRAN.

+

pboundary_left_w.ex:

+

Boundary file for left side of the domain used by PFLOTRAN.

+

pboundary_right_e.ex:

+

Boundary file for right of the domain used by PFLOTRAN.

+

pboundary_top.ex:

+

Boundary file for top of the domain used by PFLOTRAN.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/publications.html b/Documentation/sphinx-docs/build/html/publications.html new file mode 100644 index 000000000..7289c34c5 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/publications.html @@ -0,0 +1,190 @@ + + + + + + + dfnWorks Publications — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

dfnWorks Publications

+

The following are publications that use dfnWorks:

+
    +
  1. J. D. Hyman, C. W. Gable, S. L. Painter, and N. Makedonska. Conforming Delaunay triangulation of stochastically generated three dimensional discrete fracture networks: A feature rejection algorithm for meshing strategy. SIAM J. Sci. Comput. (2014).

  2. +
  3. R.S. Middleton, J.W. Carey, R.P. Currier, J. D. Hyman, Q. Kang, S. Karra, J. Jimenez-Martınez, M.L. Porter, and H.S. Viswanathan. Shale gas and non-aqueous fracturing fluids: Opportunities and challenges for supercritical CO2. Applied Energy, (2015).

  4. +
  5. J. D. Hyman, S. L. Painter, H. Viswanathan, N. Makedonska, and S. Karra. Influence of injection mode on transport properties in kilometer-scale three-dimensional discrete fracture networks. Water Resources Research (2015).

  6. +
  7. S. Karra, Nataliia Makedonska, Hari S Viswanathan, Scott L Painter, and Jeffrey D. Hyman. Effect of advective flow in fractures and matrix diffusion on natural gas production. Water Resources Research (2015).

  8. +
  9. J. D. Hyman, S. Karra, N. Makedonska, C. W Gable, S. L Painter, and H. S Viswanathan. dfnWorks: A discrete fracture network framework for modeling subsurface flow and transport. Computers & Geosciences (2015).

  10. +
  11. H. S. Viswanathan, J. D. Hyman, S. Karra, J.W. Carey, M. L. Porter, E. Rougier, R. P. Currier,Q. Kang, L. Zhou, J. Jimenez-Martınez, N. Makedonska, L. Chen, and R. S. Middleton. Using Discovery Science To Increase Efficiency of Hydraulic Fracturing While Reducing Water Usage, chapter 4, pages 71–88. ACS Publications, (2016).

  12. +
  13. N. Makedonska, S. L Painter, Q. M Bui, C. W Gable, and S. Karra. Particle tracking approach for transport in three-dimensional discrete fracture networks. Computational Geosciences (2015).

  14. +
  15. D. O’Malley, S. Karra, R. P. Currier, N. Makedonska, J. D. Hyman, and H. S. Viswanathan. Where does water go during hydraulic fracturing? Groundwater (2016).

  16. +
  17. J. D. Hyman, J Jiménez-Martínez, HS Viswanathan, JW Carey, ML Porter, E Rougier, S Karra, Q Kang, L Frash, L Chen, et al. Understanding hydraulic fracturing: a multi-scale problem. Phil. Trans. R. Soc. A, (2016).

  18. +
  19. G. Aldrich, J. D. Hyman, S. Karra, C. W. Gable, N. Makedonska, H. Viswanathan, J.Woodring, and B. Hamann. Analysis and visualization of discrete fracture networks using a flow topology graph. IEEE Transactions on Visualization and Computer Graphics (2017).

  20. +
  21. N. Makedonska, J. D. Hyman, S. Karra, S. L. Painter, C.W. Gable, and H. S. Viswanathan. Evaluating the effect of internal aperture variability on transport in kilometer scale discrete fracture networks. Advances in Water Resources (2016).

  22. +
  23. J. D. Hyman, G. Aldrich, H. Viswanathan, N. Makedonska, and S. Karra. Fracture size and transmissivity correlations: Implications for transport simulations in sparse three-dimensional discrete fracture networks following a truncated power law distribution of fracture size. Water Resources Research (2016).

  24. +
  25. H. Djidjev, D. O’Malley, H. Viswanathan, J. D. Hyman, S. Karra, and G. Srinivasan. Learning on graphs for predictions of fracture propagation, flow and transport. In 2017 IEEE International Parallel and Distributed Processing Symposium Workshops (IPDPSW) (2017).

  26. +
  27. J. D. Hyman, A. Hagberg, G. Srinivasan, J. Mohd-Yusof, and H. Viswanathan. Predictions of first passage times in sparse discrete fracture networks using graph-based reductions. Phys. Rev. E, 96:013304, Jul.

  28. +
  29. T Hadgu, S. Karra, N. Makedonska, J. D. Hyman, K. Klise, H. S. Viswanathan, and Y.Wang. A comparative study of discrete fracture network and equivalent continuum models for simulating flow and transport in the far field of a hypothetical nuclear waste repository in crystalline host rock. J. Hydrology, 2017.

  30. +
  31. V. Romano, J. D. Hyman, S. Karra, A. J. Valocchi, M. Battaglia, and S. Bigi. Numerical modeling of fluid flow in a fault zone: a case of study from majella mountain (Italy). Energy Procedia, 125:556 – 560, 2017.

  32. +
  33. M. Valera, Z. Guo, P. Kelly, S. Matz, A. Cantu, A.G. Percus, J. D. Hyman, G. Srinivasan, and H.S. Viswanathan. Machine learning for graph-based representations of three-dimensional discrete fracture networks. Computational Geosciences, (2018).

  34. +
  35. M. K. Mudunuru, S. Karra, N. Makedonska, and T. Chen. Sequential geophysical and flow inversion to characterize fracture networks in subsurface systems. Statistical Analysis and Data Mining: The ASA Data Science Journal (2017).

  36. +
  37. J. D. Hyman, Satish Karra, J. William Carey, Carl W. Gable, Hari Viswanathan, Esteban Rougier, and Zhou Lei. Discontinuities in effective permeability due to fracture percolation. Mechanics of Materials (2018).

  38. +
  39. S. Karra, D. O’Malley, J. D. Hyman, H.S. Viswanathan, and G. Srinivasan. Modeling flow and transport in fracture networks using graphs. Phys. Rev. E, (2018).

  40. +
  41. J. D. Hyman and J. Jimenéz-Martínez. Dispersion and mixing in three-dimensional discrete fracture networks: Nonlinear interplay between structural and hydraulic heterogeneity. Water Resources Research (2018).

  42. +
  43. D. O’Malley, S. Karra, J. D. Hyman, H. Viswanathan, and G. Srinivasan. Efficient Monte Carlo with graph-based subsurface flow and transport models. Water Resour. Res., (2018).

  44. +
  45. G. Srinivasan, J. D. Hyman, D. Osthus, B. Moore, D. O’Malley, S. Karra, E Rougier, A. Hagberg, A. Hunter, and H. S. Viswanathan. Quantifying topological uncertainty in fractured systems using graph theory and machine learning. Scientific Reports, (2018).

  46. +
  47. H. S. Viswanathan, J. D. Hyman, S. Karra, D. O’Malley, S. Srinivasan, A. Hagberg, and G. Srinivasan. Advancing graph-based algorithms for predicting flow and transport in fractured rock. Water Resour. Res., (2018).

  48. +
  49. S. Srinivasan, J. D. Hyman, S. Karra, D. O’Malley, H. Viswanathan, and G. Srinivasan. Robust system size reduction of discrete fracture networks: A multi-fidelity method that preserves transport characteristics. Computational Geosciences, 2018.

  50. +
  51. J. D. Hyman, Aric Hagberg, Dave Osthus, Shriram Srinivasan, Hari Viswanathan, and Gowri Srinivasan. Identifying backbones in three-dimensional discrete fracture net- works: A bipartite graph-based approach. Multiscale Modeling & Simulation (2018).

  52. +
  53. G. Aldrich, J. Lukasczyk, J. D. Hyman, G. Srinivasan, H. Viswanathan, C. Garth, H. Leitte, J. Ahrens, and B. Hamann. A query-based framework for searching, sorting, and exploring data ensembles. Computing in Science Engineering, (2018).

  54. +
  55. T. Sherman, J. D. Hyman, D. Bolster, N. Makedonska, and G. Srinivasan. Characterizing the impact of particle behavior at fracture intersections in three-dimensional discrete fracture networks. Physical Review E (2019).

  56. +
  57. J. D. Hyman, M. Dentz, A. Hagberg, and P. Kang. Linking structural and transport properties in three-dimensional fracture networks. J. Geophys. Res. Sol. Ea., (2019).

  58. +
  59. S. Srinivasan, S. Karra, J. D. Hyman, H. Viswanathan, and G. Srinivasan. Model reduction for fractured porous media: A machine-learning approach for identifying main flow pathways. Computational Geosciences (2018).

  60. +
  61. N. Makedonska, J.D, Hyman, E. Kwicklis, K. Birdsell, Conference Proceedings, Discrete Fracture Network Modeling and Simulation of Subsurface Transport for the Topopah Spring Aquifer at Pahute Mesa, 2nd International Discrete Fracture Network Engineering (2018).

  62. +
  63. N. Makedonska, C.W. Gable, R. Pawar, Conference Proceedings, Merging Discrete Fracture Network Meshes With 3D Continuum Meshes of Rock Matrix: A Novel Approach, 2nd International Discrete Fracture Network Engineering (2018).

  64. +
  65. A. Frampton, J.D, Hyman, L. Zou, Advective transport in discrete fracture networks with connected and disconnected textures representing internal aperture variability, Water Resources Research (2019).

  66. +
  67. J.D. Hyman, J. Jiménez-Martínez, C. W. Gable, P. H. Stauffer, and R. J. Pawar. Characterizing the Impact of Fractured Caprock Heterogeneity on Supercritical CO2 Injection. Transport in Porous Media (2019).

  68. +
  69. J.D. Hyman, H. Rajaram, S. Srinivasan, N. Makedonska, S. Karra, H. Viswanathan, H., & G. Srinivasan, (2019). Matrix diffusion in fractured media: New insights into power law scaling of breakthrough curves. Geophysical Research Letters (2019).

  70. +
  71. J.D. Hyman, M. Dentz, A. Hagberg, & P. K. Kang, (2019). Emergence of Stable Laws for First Passage Times in Three-Dimensional Random Fracture Networks. Physical Review Letters (2019).

  72. +
  73. M. R. Sweeney, C. W. Gable, S. Karra, P. H. Stauffer, R. J. Pawar, J. D. Hyman (2019). Upscaled discrete fracture matrix model (UDFM): an octree-refined continuum representation of fractured porous mediaComputational Geosciences (2019).

  74. +
  75. T. Sherman, J. D. Hyman, M. Dentz, and D. Bolster. Characterizing the influence of fracture density on network scale transport. J. Geophys. Res. Sol. Ea., (2019).

  76. +
  77. D. Osthus, J. D. Hyman, S. Karra, N. Panda, and G. Srinivasan. A probabilistic clustering approach for identifying primary subnetworks of discrete fracture networks with quantified uncertainty. SIAM/ASA Journal on Uncertainty Quantification, (2020).

  78. +
  79. V. Romano, S. Bigi, F. Carnevale, J. D. Hyman, S. Karra, A. Valocchi, M. Tartarello, and M. Battaglia. Hydraulic characterization of a fault zone from fracture distribution. Journal of Structural Geology, (2020).

  80. +
  81. S. Srinivasan, E. Cawi, J. D. Hyman, D. Osthus, A. Hagberg, H. Viswanathan, and G. Srinivasan. Physics-informed machine-learning for backbone identification in discrete fracture networks. Comput. Geosci., (2020).

  82. +
  83. N. Makedonska, S. Karra, H.S. Viswanathan, and G.D. Guthrie,. Role of Interaction between Hydraulic and Natural Fractures on Production. Journal of Natural Gas Science and Engineering (2020)..

  84. +
  85. H. Pham, R. Parashar, N. Sund, and K. Pohlmann. A Method to Represent a Well in a Three‐dimensional Discrete Fracture Network Model. Groundwater. (2020).

  86. +
  87. M.R. Sweeney, and J.D. Hyman. Stress effects on flow and transport in three‐dimensional fracture networks. Journal of Geophysical Research: Solid Earth. (2020).

  88. +
  89. J.D. Hyman. Flow Channeling in Fracture Networks: Characterizing the Effect of Density on Preferential Flow Path Formation. Water Resources Research (2020): e2020WR027986..

  90. +
  91. H. Pham, R. Parashar, N. Sund, and K. Pohlmann. Determination of fracture apertures via calibration of three-dimensional discrete-fracture-network models: application to Pahute Mesa, Nevada National Security Site, USA. Hydrogeol J (2020)..

  92. +
  93. S. Srinivasan, D. O’Malley, J. D. Hyman, s. Karra, H. S. Viswanathan, and G. Srinivasan Transient flow modeling in fractured media using graphs. (2020) Physical Review E..

  94. +
  95. Liangchao Zou and Vladimir Cvetkovic. Inference of Transmissivity in Crystalline Rock Using Flow Logs Under Steady‐State Pumping: Impact of Multiscale Heterogeneity. Water Resources Research (2020).

  96. +
  97. P. K. Kang, J. D. Hyman, W. S. Han, & M. Dentz, Anomalous Transport in Three‐Dimensional Discrete Fracture Networks: Interplay between Aperture Heterogeneity and Injection Modes. Water Resources Research (2020).

  98. +
  99. Hyman, J. D., & Dentz, M. Transport upscaling under flow heterogeneity and matrix-diffusion in three-dimensional discrete fracture networks. Advances in Water Resources (2021).

  100. +
  101. T. Sherman, G. Sole-Mari, J. Hyman, M. R. Sweeney, D. Vassallo, and D. Bolster. Characterizing Reactive Transport Behavior in a Three-Dimensional Discrete Fracture Network. Transport in Porous Media (2021).

  102. +
  103. S. Shriram, D. O’Malley, M. K. Mudunuru, M. R. Sweeney, J. D. Hyman, S. Karra, L. Frash et al. A machine learning framework for rapid forecasting and history matching in unconventional reservoirs. (2021) Scientific Reports.

  104. +
  105. J. D. Hyman, M. R. Sweeney, L. P. Frash, J. W. Carey, and H. S. Viswanathan. Scale‐Bridging in Three‐Dimensional Fracture Networks: Characterizing the Effects of Variable Fracture Apertures on Network‐Scale Flow Channelization. Geophysical Research Letters (2021).

  106. +
  107. Liangchao Zou and Vladimir Cvetkovic. Evaluation of Flow‐Log Data From Crystalline Rocks With Steady‐State Pumping and Ambient Flow. Geophysical Research Letters (2021).

  108. +
  109. H. Ushijima-Mwesigwa, J. D. Hyman, A. Hagberg, I. Safro, S. Karra, C. W. Gable, M. R. Sweeney, and G. Srinivasan. Multilevel graph partitioning for three-dimensional discrete fracture network flow simulations. Mathematical Geosciences (2021).

  110. +
  111. Yingtao Hu, Wenjie Xu, Liangtong Zhan, Liangchao Zou, and Yunmin Chen. “Modeling of solute transport in a fracture-matrix system with a three-dimensional discrete fracture network.” Journal of Hydrology (2021).

  112. +
  113. C. R. Romano, R. T. Williams; Evolution of Fault-Zone Hydromechanical Properties in Response to Different Cementation Processes. Lithosphere (2022).

  114. +
  115. J. Krotz, M.R. Sweeney, C.W. Gable, J.D. Hyman, & J.M. Restrepo, (2022). Variable resolution Poisson-disk sampling for meshing discrete fracture networks. Journal of Computational and Applied Mathematics (2022).

  116. +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/py-modindex.html b/Documentation/sphinx-docs/build/html/py-modindex.html new file mode 100644 index 000000000..6713dec36 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/py-modindex.html @@ -0,0 +1,348 @@ + + + + + + Python Module Index — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + +

Python Module Index

+ +
+ f | + g | + m | + p | + u +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ f
+ false_connections +
    + false_connections.py + Checks for false connections between fractures in upscaled mesh
 
+ g
+ graph_transport +
    + graph_transport.py + simulate transport on a pipe network representaiton of a DFN
 
+ m
+ map2continuum +
    + map2continuum.py + Produce octree-refined continuum mesh replacing dfn
+ mesh_dfm +
    + mesh_dfm.py + meshing driver for conforming DFM
+ mesh_dfn +
    + mesh_dfn.py + meshing driver for DFN
+ mesh_dfn_helper +
    + mesh_dfn_helper.py + helper functions for meshing DFN using LaGriT
 
+ p
+ pydfnworks +
    + pydfnworks.dfnFlow.fehm +
    + pydfnworks.dfnFlow.flow +
    + pydfnworks.dfnFlow.mass_balance +
    + pydfnworks.dfnFlow.pflotran +
    + pydfnworks.dfnGen.generation.generator +
    + pydfnworks.dfnGen.generation.input_checking +
    + pydfnworks.dfnGen.generation.input_checking.user_defined_fracture_functions +
    + pydfnworks.dfnGen.generation.output_report.gen_output +
    + pydfnworks.dfnGen.generation.stress +
    + pydfnworks.dfnGen.meshing.add_attribute_to_mesh +
    + pydfnworks.dfnGen.meshing.dfm.mesh_dfm +
    + pydfnworks.dfnGen.meshing.mapdfn_ecpm.mapdfn_ecpm +
    + pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn +
    + pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn_helper +
    + pydfnworks.dfnGen.meshing.udfm.false_connections +
    + pydfnworks.dfnGen.meshing.udfm.map2continuum +
    + pydfnworks.dfnGen.meshing.udfm.upscale +
    + pydfnworks.dfnGen.well_package.wells +
    + pydfnworks.dfnGraph.dfn2graph +
    + pydfnworks.dfnGraph.graph_flow +
    + pydfnworks.dfnGraph.graph_transport +
    + pydfnworks.dfnGraph.pruning +
    + pydfnworks.dfnTrans.transport +
 
+ u
+ upscale +
    + upscale.py + Generates PFLOTRAN or FEHM input from octree refined continuum mesh
+ + +
+
+
+ +
+ +
+

© Copyright 2020, LANL, LA-UR-17-22216.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/pydfnFlow.html b/Documentation/sphinx-docs/build/html/pydfnFlow.html new file mode 100644 index 000000000..09a731b57 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/pydfnFlow.html @@ -0,0 +1,395 @@ + + + + + + + pydfnworks: dfnFlow — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

pydfnworks: dfnFlow

+

DFN Class functions used in flow simulations (PFLOTRAN and FEHM)

+
+

Running Flow : General

+
+ +

Create symlinks to files required to run dfnFlow that are in another directory.

+
+
Parameters:
+
    +
  • self (object) – DFN Class

  • +
  • path (string) – Absolute path to primary directory.

  • +
+
+
Return type:
+

None

+
+
+

Notes

+
    +
  1. Typically, the path is DFN.path, which is set by the command line argument -path

  2. +
  3. Currently only supported for PFLOTRAN

  4. +
+
+ +
+
+dfn_flow(self, dump_vtk=True)[source]
+

Run the dfnFlow portion of the workflow

+
+
Parameters:
+
    +
  • self (object) – DFN Class

  • +
  • dump_vtk (bool) – True - Write out vtk files for flow solutions +False - Does not write out vtk files for flow solutions

  • +
+
+
+

Notes

+

Information on individual functions is found therein

+
+ +
+
+set_flow_solver(self, flow_solver)[source]
+

Sets flow solver to be used

+
+
Parameters:
+
    +
  • self (object) – DFN Class

  • +
  • flow_solver (string) – Name of flow solver. Currently supported flow sovlers are FEHM and PFLOTRAN

  • +
+
+
+

Notes

+

Default is PFLOTRAN

+
+ +
+
+

Running Flow: PFLOTRAN

+

functions for using pflotran in dfnworks

+
+
+lagrit2pflotran(self, boundary_cell_area=None)[source]
+

Takes output from LaGriT and processes it for use in PFLOTRAN. +Calls the function write_perms_and_correct_volumes_areas() and zone2ex

+
+
Parameters:
+

self (object) – DFN Class

+
+
Return type:
+

None

+
+
+

Notes

+

None

+
+ +
+
+parse_pflotran_vtk_python(self, grid_vtk_file='')[source]
+

Adds CELL_DATA to POINT_DATA in the VTK output from PFLOTRAN. +:param self: DFN Class +:type self: object +:param grid_vtk_file: Name of vtk file with mesh. Typically local_dfnFlow_file.vtk +:type grid_vtk_file: string

+
+
Return type:
+

None

+
+
+

Notes

+

If DFN class does not have a vtk file, inp2vtk_python is called

+
+ +
+
+pflotran(self, transient=False, restart=False, restart_file='')[source]
+

Run PFLOTRAN. Copy PFLOTRAN run file into working directory and run with ncpus

+
+
Parameters:
+
    +
  • self (object) – DFN Class

  • +
  • transient (bool) – Boolean if PFLOTRAN is running in transient mode

  • +
  • restart (bool) – Boolean if PFLOTRAN is restarting from checkpoint

  • +
  • restart_file (string) – Filename of restart file

  • +
+
+
Return type:
+

None

+
+
+

Notes

+

Runs PFLOTRAN Executable, see http://www.pflotran.org/ for details on PFLOTRAN input cards

+
+ +
+
+pflotran_cleanup(self, index_start=0, index_finish=1, filename='')[source]
+

Concatenate PFLOTRAN output files and then delete them

+
+
Parameters:
+
    +
  • self (object) – DFN Class

  • +
  • index (int) – If PFLOTRAN has multiple dumps use this to pick which dump is put into cellinfo.dat and darcyvel.dat

  • +
+
+
Return type:
+

None

+
+
+

Notes

+

Can be run in a loop over all pflotran dumps

+
+ +
+
+write_perms_and_correct_volumes_areas(self)[source]
+

Write permeability values to perm_file, write aperture values to aper_file, and correct volume areas in uge_file

+
+
Parameters:
+

self (object) – DFN Class

+
+
Return type:
+

None

+
+
+

Notes

+

Calls executable correct_uge

+
+ +
+
+zone2ex(self, zone_file='', face='', boundary_cell_area=0.1)[source]
+

Convert zone files from LaGriT into ex format for LaGriT

+
+
Parameters:
+
    +
  • self (object) – DFN Class

  • +
  • zone_file (string) – Name of zone file

  • +
  • Face (Face of the plane corresponding to the zone file)

  • +
  • zone_file – Name of zone file to work on. Can be ‘all’ processes all directions, top, bottom, left, right, front, back

  • +
  • boundary_cell_area (double) – should be a large value relative to the mesh size to force pressure boundary conditions.

  • +
+
+
Return type:
+

None

+
+
+

Notes

+

the boundary_cell_area should be a function of h, the mesh resolution

+
+ +
+
+

Running Flow: FEHM

+
+
+correct_stor_file(self)[source]
+

Corrects volumes in stor file to account for apertures

+
+
Parameters:
+

self (object) – DFN Class

+
+
Return type:
+

None

+
+
+

Notes

+

Currently does not work with cell based aperture

+
+ +
+
+fehm(self)[source]
+

Run FEHM

+
+
Parameters:
+

self (object) – DFN Class

+
+
Return type:
+

None

+
+
+

Notes

+

See https://fehm.lanl.gov/ for details about FEHM

+
+ +
+
+

Processing Flow

+
+
+effective_perm(self, inflow_pressure, outflow_pressure, boundary_file, direction, darcy_vel_file='darcyvel.dat')[source]
+

Computes the effective permeability of a DFN in the primary direction of flow using a steady-state PFLOTRAN solution.

+
+
Parameters:
+
    +
  • self (object) – DFN Class

  • +
  • inflow_pressure (float) – Pressure at the inflow boundary face. Units are Pascal

  • +
  • outflow_pressure (float) – Pressure at the outflow boundary face. Units are Pascal

  • +
  • boundary_file (string) – Name of inflow boundary file, e.g., pboundary_left.ex

  • +
  • direction (string) – Primary direction of flow, x, y, or z

  • +
  • darcy_vel_file (string) – Name of concatenated Darcy velocity file

  • +
+
+
Return type:
+

None

+
+
+

Notes

+
    +
  1. Information is written to screen and to the file self.local_jobname_effective_perm.txt

  2. +
  3. Currently, only PFLOTRAN solutions are supported

  4. +
  5. Assumes density of water at 20c

  6. +
+
+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/pydfnGen.html b/Documentation/sphinx-docs/build/html/pydfnGen.html new file mode 100644 index 000000000..2aab08f0f --- /dev/null +++ b/Documentation/sphinx-docs/build/html/pydfnGen.html @@ -0,0 +1,930 @@ + + + + + + + pydfnworks: dfnGen — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

pydfnworks: dfnGen

+

DFN Class functions used in network generation and meshing

+
+

dfnGen

+
+

Adding Fracture Families

+
+
+add_fracture_family(self, shape, distribution, kappa, family_number=None, probability=None, p32=None, layer=0, region=0, number_of_points=8, aspect=1, beta_distribution=0, beta=0, theta=None, phi=None, strike=None, dip=None, trend=None, plunge=None, alpha=None, log_mean=None, log_std=None, exp_mean=None, constant=None, min_radius=None, max_radius=None, hy_variable=None, hy_function=None, hy_params=None)[source]
+

Generates a fracture family

+
+
Parameters:
+
    +
  • self (DFN object)

  • +
  • shape ('rect' or 'ell' deines the fracture family shape)

  • +
  • distribution ('tpl', 'log_normal', 'exp', or 'constant' defines the sample distribution for the fracture radius)

  • +
  • kappa (concentration param of the von Mises-Fisher distribution)

  • +
  • family_number (fracutre family id. default = None)

  • +
  • probability (probabily of a fracture belonging to this family. default = None. use if stopCondition = 0)

  • +
  • p32 (fracture intensity for the family. default = None. use if stopCondition = 1)

  • +
  • layer (assigns fracture family to a layer in the domain. default = 0)

  • +
  • region (assigns fracture family to a region in the domain. default = 0)

  • +
  • number_of_points (specifies the number of vertices defining th eboundary of each fracture. default = 8)

  • +
  • aspect (the aspect ratio of the fractures. default = 1)

  • +
  • beta_distribution (0 (uniform distribtuion [0,2pi) or 1 (constant rotation specfied by ebeta) rotation of each fractures normal vector. default 0)

  • +
  • beta (angle fo constant rotation. use if beta_distribution = 1. default = 0)

  • +
  • theta (use if orientationOption = 0 (default). default = None)

  • +
  • phi (use if orientationOption = 0 (default). default = None)

  • +
  • trend (use if orientationOption = 1. default = None)

  • +
  • plunge (use if orientationOption = 1. default = None)

  • +
  • dip (use if orientationOption = 2. default = None)

  • +
  • strike (use if orientationOption = 2. default = None)

  • +
  • alpha (parameter for 'tpl'. default = None)

  • +
  • log_mean (parameter for 'log_normal'. default = None)

  • +
  • log_std (parameter for 'log_normal'. default = None)

  • +
  • exp_mean (parameter for 'exp'. default = None)

  • +
  • constant (parameter for 'constant'. default = None)

  • +
  • min_radius (minimum fracture radius for 'tpl' 'log_normal' or 'exp'. default = None)

  • +
  • max_radius (maximum fracture radius for 'tpl' 'log_normal' or 'exp'. default = None)

  • +
  • hy_variable (hydraulic variable to assign values to. options are 'aperture', 'permeability', 'transmissivity',)

  • +
  • hy_function (relationship between hydraulic variable and fracture radius. options are 'correlated', 'semi-correlated', 'constant', 'log-normal')

  • +
  • hy_params (parameters for the hydraulic function. see next lines for syntax and options) – if ‘correlated’ –> {“alpha”:value, “beta:value} +if ‘semi-correlated’ –> {“alpha”:value, “beta”:value, “sigma”:value} +if ‘constant’ –> {“mu”:value} +if ‘log-normal’ –> {“mu”:value, “sigma”:value}

  • +
+
+
Return type:
+

Populated fracture family dictionary for specified family

+
+
+

Notes

+

See https://dfnworks.lanl.gov/dfngen.html#domain-parameters for more +information about parameters

+
+ +

Example:

+
DFN.add_fracture_family(shape="ell",
+                    distribution="tpl",
+                    alpha=1.8,
+                    min_radius=1.0,
+                    max_radius=5.0,
+                    kappa=1.0,
+                    theta=0.0,
+                    phi=0.0,
+                    aspect=2,
+                    beta_distribution=1,
+                    beta=45.0,
+                    p32=1.1,
+                    hy_variable='aperture',
+                    hy_function='correlated',
+                    hy_params={
+                        "alpha": 10**-5,
+                        "beta": 0.5
+                    })
+
+
+
+
+

Adding User Fractures

+
+
+add_user_fract(self, shape, radii, translation, filename=None, aspect_ratio=1, beta=0, angle_option='degree', orientation_option='normal', normal_vector=None, trend_plunge=None, dip_strike=None, number_of_vertices=None, permeability=None, transmissivity=None, aperture=None)[source]
+

Specifies user defined fracture parameters for the DFN.

+
+
Parameters:
+
    +
  • shape (string) – The desired shape of the fracture options are ‘rect’, ‘ell’, and ‘poly’ - Required

  • +
  • radii (float) – 1/2 size of the fracture in meters - Required

  • +
  • translation (list of floats [3]) – Fracture center

  • +
  • filename (string) – The name of the user defined fracture file. Default is user_defined_{shape}.dat

  • +
  • aspect_ratio (float) – Fracture aspect ratio

  • +
  • beta (float) – Rotation angle around center of the fracture

  • +
  • angle_option (string) – Angle option ‘degree’ or ‘radian’. Default is degree

  • +
  • orientation_option (string) – Choice of fracture orienation ‘normal’, ‘trend_plunge’, ‘dip_strike’

  • +
  • normal_vector (list [3]) – normal vector of the fracture

  • +
  • trend_plunge (list [2]) – trend and plunge of the fracture

  • +
  • dip_strike (list [2]) – dip and strike of the fracture

  • +
  • number_of_vertices (int) – Number of vertices on the fracture boundary.

  • +
  • permeability (float) – Permeability of the fracture

  • +
  • transmissivity (float) – Fracture Tramsmissivity

  • +
  • aperture (float) – Hydraulic aperture of the fracture

  • +
+
+
Return type:
+

None - fracture dictionaries are attached to the DFN object

+
+
+

Notes

+

Please be aware, the user fracture files can only be automatically written for +ellipses and rectangles not specified by coordinate.

+

See

+

https://dfnworks.lanl.gov/dfngen.html#user-defined-fracture-generation-parameters

+

for additional information

+
+ +

Example:

+
DFN.add_user_fract(shape='ell',
+               radii=.4,
+               aspect_ratio=1,
+               translation=[0.2, 0, 0.2],
+               normal_vector=[0, 0, 1],
+               number_of_vertices=8,
+               aperture=1.0e-5)
+
+
+
+
+

Adding User Fractures From a File

+
+
+add_user_fract_from_file(self, filename, shape, nPolygons, by_coord=False, aperture=None, transmissivity=None, permeability=None)[source]
+

Sets up paths for fractures defined in user input file. When inserting user fractures from file, hydraulic properties must be provided as a list of length nPolygons (number of fractures defined in the file)

+
+
Parameters:
+
    +
  • filename (string) – path to source file

  • +
  • shape (string) – The shape of the fracture options are ‘rect’, ‘ell’, and ‘poly’ - Required

  • +
  • by_coord (boolean) – True / False of file format for coordinate or general input

  • +
  • nPolygons (int) – The number of polygons specified in the file

  • +
  • permeability (list or array) – Permeabilities of the fractures

  • +
  • transmissivity (list or array) – Fracture Tramsmissivities

  • +
  • aperture (list or array) – Hydraulic apertures of the fracture

  • +
+
+
Return type:
+

None

+
+
+

Notes

+

Does not write the file, only sets up paths

+

~/src/dfnworks-aidan/pydfnworks/pydfnworks/

+
+ +

Example:

+
DFN.add_user_fract_from_file(shape="poly",
+               filename = f'{src_path}/polygons.dat',
+               permeability = 1e-12)
+
+
+
+ +
+

Processing Generator Input

+
+
+check_input(self, from_file=False)[source]
+

Checks input file for DFNGen to make sure all necessary parameters are defined. Then writes out a “clean” version of the input file

+
+
+
Input Format Requirements:
    +
  • Each parameter must be defined on its own line (separate by newline)

  • +
  • A parameter (key) MUST be separated from its value by a colon ‘:’ (ie. –> key: value)

  • +
  • Values may also be placed on lines after the ‘key’

  • +
  • Comment Format: On a line containing // or / *, nothing after * / or // will be processed but text before a comment will be processed

  • +
+
+
+
+
+
Parameters:
+

self (DFN Class Object)

+
+
Return type:
+

None

+
+
+

Notes

+

There are warnings and errors raised in this function. Warning will let you continue while errors will stop the run. Continue past warnings are your own risk.

+

From File feature is no longer maintained. Functions should be removed in the near future.

+
+ +
+
+

Running the Generator

+
+
+create_network(self)[source]
+

Execute dfnGen

+
+
Parameters:
+

self – DFN object

+
+
Return type:
+

None

+
+
+

Notes

+

After generation is complete, this script checks whether the generation of the fracture network failed or succeeded based on the existence of the file params.txt.

+
+ +
+
+dfn_gen(self, output=True)[source]
+
+
Wrapper script the runs the dfnGen workflow:
    +
  1. make_working_directory: Create a directory with name of job

  2. +
  3. check_input: Check input parameters and create a clean version of the input file

  4. +
  5. create_network: Create network. DFNGEN v2.0 is called and creates the network

  6. +
  7. output_report: Generate a PDF summary of the DFN generation

  8. +
  9. mesh_network: calls module dfnGen_meshing and runs LaGriT to mesh the DFN

  10. +
+
+
+
+
Parameters:
+
    +
  • self – DFN object

  • +
  • output (bool) – If True, output pdf will be created. If False, no pdf is made

  • +
  • visual_mode (None) – If the user wants to run in a different meshing mode from what is in params.txt, set visual_mode = True/False on command line to override meshing mode

  • +
+
+
Return type:
+

None

+
+
+

Notes

+

Details of each portion of the routine are in those sections

+
+ +
+
+grab_polygon_data(self)[source]
+

If flag self.store_polygon_data is set to True, the information stored in polygon.dat is written to a dictionary self.polygons. +To access the points that define an individual polygon, call self.polygons[f’poly{i}’] where i is a number between 1 and the number of defined polygons. This returns an array of coordinates in the format np.array([x1,y1,z1],[x2,y2,z2],…[xn,yn,zn])

+
+
Parameters:
+

self (DFN object)

+
+
Return type:
+

None

+
+
+

Notes

+

None

+
+ +
+
+make_working_directory(self, delete=False)[source]
+

Make working directory for dfnWorks Simulation

+
+
Parameters:
+
    +
  • self – DFN object

  • +
  • delete (bool) – If True, deletes the existing working directory. Default = False

  • +
+
+
Return type:
+

None

+
+
+

Notes

+

If directory already exists, user is prompted if they want to overwrite and proceed. If not, program exits.

+
+ +
+
+

Analysis of Generated DFN

+
+
filename:
+

gen_output.py

+
+
synopsis:
+

Main driver for dfnGen output report

+
+
version:
+

1.0

+
+
maintainer:
+

Jeffrey Hyman

+
+
moduleauthor:
+

Jeffrey Hyman <jhyman@lanl.gov>

+
+
+
+
+output_report(self, verbose=True, output_dir='dfnGen_output_report')[source]
+

Creates a PDF output report for the network created by DFNGen. Plots of the fracture lengths, locations, orientations are produced for each family. Files are written into “output_dir/family_{id}/”. Information about the whole network are also created and written into “output_dir/network/”

+
+
Parameters:
+
    +
  • self (object) – DFN Class object

  • +
  • verbose (bool) – Toggle for the amount of information printed to screen. If true, progress information printed to screen

  • +
  • output_dir (string) – Name of directory where all plots are saved

  • +
+
+
Return type:
+

None

+
+
+

Notes

+

Final output report is named “jobname”_output_report.pdf +User defined fractures (ellipses, rectangles, and polygons) are not supported at this time.

+
+ +
+
+

Additional Information on the Modification of Hydraulic Properties of the DFN

+

Hydraulic properties can be assigned to fractures based on four different models. One can assign hydraulic aperture b, permeability, k, or transmissivity T. Below we present the functions for hydraulic aperture, but the equations for other values are the same.

+

The first is a perfectly correlated model where the hydraulic property is a function of the fracture radius

+
+

b = \alpha r^\beta

+

The keyword for this model is correlated.

+

The second is a semi-correlated correlated model where the hydraulic property is a function of the fracture radius

+
+

\log_{10}(b) = \log_{10}(\alpha r^\beta) + \sigma \mathcal{N}(0,1)

+

where a stochastic term is included into the correlated model +to account for uncertainty and variability between fractures of the same size. The strength of the stochastic term is determined by the variance of a log-normal distribution \sigma and the stochastic term is an independent identically distributed random variable sampled from a normal distribution with mean 0 and variance 1, \mathcal{N}(0,1). This model results in a log-normal distribution of fracture transmissivities around a positively cor- related power law mean. We refer to this model as semicorrelated.

+

The keyword for this model is semi-correlated.

+

The third model assumes that there is no correlation between the fracture size and transmissivity and all values are independent identically distributed random variables from a log-normal distribution with speci- fied mean \mu and variance \sigma,

+
+

\log_{10}(b) = \mu + \sigma \mathcal{N}(0,1)

+

The keyword for this model is log-normal.

+

The fourth model represents an assumption that in addition to no relationship between size and hydraulic properties, there is no variation between fractures

+
+

b = \mu

+

The keyword for this model is constant.

+

Notes:

+

See Hyman et al. 2016 “Fracture size and transmissivity correlations: Implications for transport simulations in sparse three-dimensional discrete fracture networks following a truncated power law distribution of fracture size” Water Resources Research for more details

+

Changes in hydraulic properties are assigned when defining a fracture family or user defined fracture. User defined fractures currently only support constant hydraulic properties.

+
+
+

Modification of hydraulic properties of the DFN based on background stress field

+
+
+stress_based_apertures(self, sigma_mat, friction_angle=25.0, dilation_angle=5, critical_shear_displacement=0.003, shear_modulus=10000000000.0, min_b=1e-10, shear_stiffness=400000000000.0)[source]
+

Takes stress tensor as input (defined in dfn run file) and calculates new apertures based on Bandis equations. New aperture and permeability values are written to files.

+
+
Parameters:
+
    +
  • sigma_mat (array) – 3 x 3 stress tensor (units in Pa)

  • +
  • friction_angle (float) – Friction angle (Degrees)

  • +
  • dilation_angle (float) – Dilation angle (Degrees)

  • +
  • critical_shear_displacement (float) – Critical shear displacement

  • +
  • shear_modulus (float) – Shear modulus (Pa)

  • +
  • min_b (float) – Minimum aperture (m)

  • +
  • shear_stiffness (float) – Shear stiffness (Pa/m)

  • +
+
+
Return type:
+

None

+
+
+

Notes

+

For details of implementation see

+

“Sweeney, Matthew Ryan, and J. D. Hyman. “Stress effects on flow and transport in three‐dimensional fracture networks.” Journal of Geophysical Research: Solid Earth 125.8 (2020): e2020JB019754.”

+

and

+

Baghbanan, Alireza, and Lanru Jing. “Stress effects on permeability in a fractured rock mass with correlated fracture length and aperture.” International journal of rock mechanics and mining sciences 45.8 (2008): 1320-1334.

+

and

+

Zhao, Zhihong, et al. “Impact of stress on solute transport in a fracture network: A comparison study.” Journal of Rock Mechanics and Geotechnical Engineering 5.2 (2013): 110-123.

+
+ +
+
+
+

Meshing - LaGriT

+
+

Primary DFN meshing driver

+
+
+mesh_network(self, uniform_mesh=False, min_dist=0.5, max_dist=10, max_resolution_factor=10, well=False, cleanup=True, strict=True, quiet=True)[source]
+
+

Mesh fracture network using LaGriT

+
+
+
Parameters:
+
    +
  • self (object) – DFN Class

  • +
  • uniform_mesh (bool) – toggle for uniform or variable mesh. Default : False

  • +
  • min_dist (float) – Defines the minimum distance from the intersections with resolution h/2. This value is the factor of h, distance = min_dist * h

  • +
  • max_dist (float) – Defines the minimum distance from the intersections with resolution max_resolution * h. This value is the factor of h, distance = max_dist * h

  • +
  • max_resolution_factor (float) – Maximum factor of the mesh resolultion (max_resolution *h). Depending on the slope of the linear function and size of the fracture, this may not be realized in the mesh.

  • +
  • cleanup (bool) – toggle to clean up directory (remove meshing files after a run). Default : True

  • +
  • strict (bool) – Toggle if a few mesh errors are acceptable. default is true

  • +
  • quiet (bool) – Toggle to turn on/off verbose information to screen about meshing. Default is true, does not print to screen

  • +
+
+
Return type:
+

None

+
+
+

Notes

+
    +
  1. All fractures in self.prune_file must intersect at least 1 other fracture

  2. +
+
+ +
+
+

Meshing helper methods

+
+ +

Makes symlinks for files in path required for meshing

+
+
Parameters:
+
    +
  • self (DFN object)

  • +
  • path (string) – Path to where meshing files are located

  • +
+
+
Return type:
+

None

+
+
+

Notes

+

None

+
+ +
+
+inp2gmv(self, inp_file=None)[source]
+

Convert inp file to gmv file, for general mesh viewer. Name of output file for base.inp is base.gmv

+
+
Parameters:
+
    +
  • self (object) – DFN Class

  • +
  • inp_file (str) – Name of inp file if not an attribure of self

  • +
+
+
Return type:
+

None

+
+
+

Notes

+
+ +
+
+inp2vtk_python(self)[source]
+

Using Python VTK library, convert inp file to VTK file.

+
+
Parameters:
+

self (object) – DFN Class

+
+
Return type:
+

None

+
+
+

Notes

+

For a mesh base.inp, this dumps a VTK file named base.vtk

+
+ +
+
+run_lagrit_script(lagrit_file, output_file=None, quiet=False)[source]
+

Runs LaGriT

+
+
Parameters:
+

----------

+
lagrit_filestring

Name of LaGriT script to run

+
+
output_filestring

Name of file to dump LaGriT output

+
+
quietbool

If false, information will be printed to screen.

+
+
+

+
+
Returns:
+

failure – If the run was successful, then 0 is returned.

+
+
Return type:
+

int

+
+
+
+ +
+
+add_variable_to_mesh(self, variable, variable_file, mesh_file_in, mesh_file_out=None, node_based=False)[source]
+

Adds a variable to the nodes of a mesh. Can be either fracture (material) based +or node based.

+
+
Parameters:
+
    +
  • self (object) – DFN Class

  • +
  • variable (string) – name of variable

  • +
  • variable_file (string) – name of file containing variable files. Must be a single column where each line corresponds to that node number in the mesh

  • +
  • mesh_file_in (string) – Name of source mesh file

  • +
  • mesh_file_out (string) – Name of Target mesh file. If no name if provide, mesh_file_in will be used

  • +
  • node_based (bool) – Set to True if variable_file contains node-based values, Set to False +if variable_file provide fracture based values

  • +
+
+
Returns:
+

lagrit_file – Name of LaGriT output file

+
+
Return type:
+

string

+
+
+
+ +
+
+
+

UDFM

+
+

Creating an upscaled mesh of the DFN (UDFM)

+
+
+map_to_continuum(self, l, orl, path='./', dir_name='octree')[source]
+

This function generates an octree-refined continuum mesh using the +reduced_mesh.inp as input. To generate the reduced_mesh.inp, one must +turn visualization mode on in the DFN input card.

+
+
Parameters:
+
    +
  • self (object) – DFN Class

  • +
  • l (float) – Size (m) of level-0 mesh element in the continuum mesh

  • +
  • orl (int) – Number of total refinement levels in the octree

  • +
  • path (string) – path to primary DFN directory

  • +
  • dir_name (string) – name of directory where the octree mesh is created

  • +
+
+
Return type:
+

None

+
+
+

Notes

+
+
octree_dfn.inpMesh file

Octree-refined continuum mesh

+
+
fracX.inpMesh files

Octree-refined continuum meshes, which contain intersection areas

+
+
+
+ +
+
+upscale(self, mat_perm, mat_por, path='../')[source]
+

Generate permeabilities and porosities based on output of map2continuum.

+
+
Parameters:
+
    +
  • self (object) – DFN Class

  • +
  • mat_perm (float) – Matrix permeability (in m^2)

  • +
  • mat_por (float) – Matrix porosity

  • +
+
+
Returns:
+

    +
  • perm_fehm.dat (text file) – Contains permeability data for FEHM input

  • +
  • rock_fehm.dat (text file) – Contains rock properties data for FEHM input

  • +
  • mesh_permeability.h5 (h5 file) – Contains permeabilites at each node for PFLOTRAN input

  • +
  • mesh_porosity.h5 (h5 file) – Contains porosities at each node for PFLOTRAN input

  • +
+

+
+
+

Notes

+

None

+
+ +
+
+check_false_connections(self, path='../')[source]
+
+
Parameters:
+
    +
  • self (object) – DFN Class

  • +
  • fmc_filname (string) – name of the pickled dictionary of mesh and fracture intersections

  • +
+
+
Returns:
+

    +
  • num_false_connections (int) – number of false connections

  • +
  • num_cell_false (int) – number of Voronoi cells with false connections

  • +
  • false_connections (list) – list of tuples of false connections created by upscaling

  • +
+

+
+
+

Notes

+

map2continuum and upscale must be run first to create the fracture/mesh intersection +dictionary. Thus must be run in the main job directory which contains connectivity.dat

+
+ +
+
+
+

Map-DFN upscaling

+

mapdfn2pflotran.py

+

Call methods in mapdfn.py to take output of dfnWorks-Version2.0, create +equivalent continuous porous medium representation, and write parameters +(permeability, porosity, tortuosity) to files for use with PFLOTRAN.

+
+
Usage: Edit values for origin, nx, ny, nz, d, k_background, bulk_por,

tortuosity factor, and h5origin. +Paths and filenames are hardwired and may also need to be checked. +As written, they assume script is being called from a subdirectory. +Then: python mapdfn2pflotran.py

+
+
Dependencies: mapdfn.py

numpy +h5py

+
+
+

Author:

+

Date: 07/13/18 +SAND Number: SAND2018-7605 O

+
+
+mapdfn_ecpm(self, matrix_perm, matrix_porosity, cell_size, matrix_on=False, tortuosity_factor=0.001, lump_diag_terms=False, correction_factor=True, output_dir='mapdfn_ecpm')[source]
+

This script takes the top-level directory of the dfn and maps it to an ecpm, saving the ecpm files in that directory

+
+
Parameters:
+
    +
  • self (dfnWorks object)

  • +
  • cell_size (float) – The cell size (meters) to use for the meshing

  • +
  • correction_factor (boolean) – Apply stairstep correction from EDFM to not applied to permeability

  • +
+
+
Return type:
+

None

+
+
+
+

Authors

+
+

Emily Stein (ergiamb@sandia.gov) +Applied Systems Analysis and Research, 8844 +Sandia National Laboratories

+

Edited by Teresa Portone (tporton@sandia.gov) 11/2020 to take arguments.

+

Rosie Leone

+

Jeffrey Hyman 07/2023 - Integration with pydfnWorks

+
+

Notes

+
+
+ +
+
+

DFM

+
+

Creating a conforming DFM mesh DFN

+
+
+mesh_dfm(self, dirname='dfm_mesh', allowed_percentage=1, psets=False, cleanup=True)[source]
+

“ Creates a conforming mesh of a DFN using a uniform background tetrahedron mesh. The DFN must be meshed using a uniform triangular mesh. (DFN.mesh_network(uniform_mesh = True))

+
+
Parameters:
+
    +
  • dirname (string) – name of working directory. Default : dfm_mesh

  • +
  • allowed_percentage (float) – Percentage of the mesh allowed to be missing and still continue

  • +
  • cleanup (bool) – Clean up working directory. If true dep files are moved into subdirectories

  • +
+
+
Return type:
+

None

+
+
+

Notes

+

The final mesh is output in exodus format. This requires that LaGriT is built against exodus.

+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/pydfnGraph.html b/Documentation/sphinx-docs/build/html/pydfnGraph.html new file mode 100644 index 000000000..40a74d3a1 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/pydfnGraph.html @@ -0,0 +1,405 @@ + + + + + + + pydfnworks: dfnGraph — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

pydfnworks: dfnGraph

+

DFN Class functions used in graph analysis and pipe-network simulations

+
+

General Graph Functions

+
+
+add_fracture_source(self, G, source)[source]
+
+
Parameters:
+
    +
  • G (NetworkX Graph) – NetworkX Graph based on a DFN

  • +
  • source_list (list) – list of integers corresponding to fracture numbers

  • +
  • remove_old_source (bool) – remove old source from the graph

  • +
+
+
Returns:
+

G

+
+
Return type:
+

NetworkX Graph

+
+
+

Notes

+

bipartite graph not supported

+
+ +
+
+add_fracture_target(self, G, target)[source]
+
+
Parameters:
+
    +
  • G (NetworkX Graph) – NetworkX Graph based on a DFN

  • +
  • target (list) – list of integers corresponding to fracture numbers

  • +
+
+
Returns:
+

G

+
+
Return type:
+

NetworkX Graph

+
+
+

Notes

+

bipartite graph not supported

+
+ +
+
+create_graph(self, graph_type, inflow, outflow)[source]
+

Header function to create a graph based on a DFN. Particular algorithms are in files.

+
+
Parameters:
+
    +
  • self (object) – DFN Class object

  • +
  • graph_type (string) – Option for what graph representation of the DFN is requested. Currently supported are fracture, intersection, and bipartitie

  • +
  • inflow (string) – Name of inflow boundary (connect to source)

  • +
  • outflow (string) – Name of outflow boundary (connect to target)

  • +
+
+
Returns:
+

G – Graph based on DFN

+
+
Return type:
+

NetworkX Graph

+
+
+

Notes

+
+ +
+
+dump_fractures(self, G, filename)[source]
+

Write fracture numbers assocaited with the graph G out into an ASCII file inputs

+
+
Parameters:
+
    +
  • self (object) – DFN Class

  • +
  • G (NetworkX graph) – NetworkX Graph based on the DFN

  • +
  • filename (string) – Output filename

  • +
+
+
+

Notes

+
+ +
+
+dump_json_graph(self, G, name)[source]
+

Write graph out in json format

+
+
Parameters:
+
    +
  • self (object) – DFN Class

  • +
  • G (networkX graph) – NetworkX Graph based on the DFN

  • +
  • name (string) – Name of output file (no .json)

  • +
+
+
+

Notes

+
+ +
+
+load_json_graph(self, name)[source]
+

Read in graph from json format

+
+
Parameters:
+
    +
  • self (object) – DFN Class

  • +
  • name (string) – Name of input file (no .json)

  • +
+
+
Returns:
+

G – NetworkX Graph based on the DFN

+
+
Return type:
+

networkX graph

+
+
+
+ +
+
+plot_graph(self, G, source='s', target='t', output_name='dfn_graph')[source]
+

Create a png of a graph with source nodes colored blue, target red, and all over nodes black

+
+
Parameters:
+
    +
  • G (NetworkX graph) – NetworkX Graph based on the DFN

  • +
  • source (node) – Starting node

  • +
  • target (node) – Ending node

  • +
  • output_name (string) – Name of output file (no .png)

  • +
+
+
+

Notes

+

Image is written to output_name.png

+
+ +
+
+greedy_edge_disjoint(self, G, source='s', target='t', weight='None', k='')[source]
+

Greedy Algorithm to find edge disjoint subgraph from s to t. +See Hyman et al. 2018 SIAM MMS

+
+
Parameters:
+
    +
  • self (object) – DFN Class Object

  • +
  • G (NetworkX graph) – NetworkX Graph based on the DFN

  • +
  • source (node) – Starting node

  • +
  • target (node) – Ending node

  • +
  • weight (string) – Edge weight used for finding the shortest path

  • +
  • k (int) – Number of edge disjoint paths requested

  • +
+
+
Returns:
+

H – Subgraph of G made up of the k shortest of all edge-disjoint paths from source to target

+
+
Return type:
+

NetworkX Graph

+
+
+

Notes

+
    +
  1. Edge weights must be numerical and non-negative.

  2. +
  3. See Hyman et al. 2018 “Identifying Backbones in Three-Dimensional Discrete Fracture Networks: A Bipartite Graph-Based Approach” SIAM Multiscale Modeling and Simulation for more details

  4. +
+
+ +
+
+k_shortest_paths_backbone(self, G, k, source='s', target='t', weight=None)[source]
+

Returns the subgraph made up of the k shortest paths in a graph

+
+
Parameters:
+
    +
  • G (NetworkX Graph) – NetworkX Graph based on a DFN

  • +
  • k (int) – Number of requested paths

  • +
  • source (node) – Starting node

  • +
  • target (node) – Ending node

  • +
  • weight (string) – Edge weight used for finding the shortest path

  • +
+
+
Returns:
+

H – Subgraph of G made up of the k shortest paths

+
+
Return type:
+

NetworkX Graph

+
+
+

Notes

+

See Hyman et al. 2017 “Predictions of first passage times in sparse discrete fracture networks using graph-based reductions” Physical Review E for more details

+
+ +
+
+

Graph-Based Flow and Transport

+
+
+run_graph_flow(self, inflow, outflow, pressure_in, pressure_out, fluid_viscosity=0.00089, phi=1, G=None, graph_flow_name='graph_flow.hdf5')[source]
+

Solve for pressure driven steady state flow on a graph representation of the DFN.

+
+
Parameters:
+
    +
  • self (object) – DFN Class

  • +
  • inflow (string) – name of file containing list of DFN fractures on inflow boundary

  • +
  • outflow (string) – name of file containing list of DFN fractures on outflow boundary

  • +
  • pressure_in (double) – Value of pressure at inlet [Pa]

  • +
  • pressure_out (double) – Value of pressure at outlet [Pa]

  • +
  • fluid_viscosity (double) – optional, default is for water. [Pa*s]

  • +
  • phi (double) – Fracture porosity, default is 1 [-]

  • +
  • G (Input Graph)

  • +
+
+
Returns:
+

Gtilde – Gtilde is a directed acyclic graph with vertex pressures, fluxes, velocities, volumetric flow rates, and travel times

+
+
Return type:
+

NetworkX graph

+
+
+
+ +
+
+run_graph_transport(self, G, nparticles, partime_file, frac_id_file=None, format='hdf5', initial_positions='uniform', dump_traj=False, tdrw_flag=False, matrix_porosity=None, matrix_diffusivity=None, fracture_spacing=None, control_planes=None, direction=None, cp_filename='control_planes')[source]
+

Run particle tracking on the given NetworkX graph

+
+
Parameters:
+
    +
  • self (object) – DFN Class

  • +
  • G (NetworkX graph) – obtained from graph_flow

  • +
  • nparticles (int) – number of particles

  • +
  • initial_positions (str) – distribution of initial conditions. options are uniform and flux (flux-weighted)

  • +
  • partime_file (string) – name of file to which the total travel times and lengths will be written for each particle

  • +
  • frac_id_file (string) – name of file to which detailed information of each particle’s travel will be written

  • +
  • dump_flag (bool) – on/off to write full trajectory information to file

  • +
  • tdrw_flag (Bool) – if False, matrix_porosity and matrix_diffusivity are ignored

  • +
  • matrix_porosity (float) – Matrix Porosity used in TDRW

  • +
  • matrix_diffusivity (float) – Matrix Diffusivity used in TDRW (SI units m^2/s)

  • +
  • fracture_spaceing (float) – finite block size for limited matrix diffusion

  • +
  • control_planes (list of floats) – list of control plane locations to dump travel times. Only in primary direction of flow.

  • +
  • direction (primary) – string indicating primary direction of flow

  • +
+
+
Returns:
+

particles – list of particles objects

+
+
Return type:
+

list

+
+
+

Notes

+

Information on individual functions is found therein

+
+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/pydfnTrans.html b/Documentation/sphinx-docs/build/html/pydfnTrans.html new file mode 100644 index 000000000..aac3f3c31 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/pydfnTrans.html @@ -0,0 +1,220 @@ + + + + + + + pydfnworks: dfnTrans — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

pydfnworks: dfnTrans

+

DFN Class functions used in particle transport simulations (DFNTrans)

+
+

Running Transport Simulations

+
+
+check_dfn_trans_run_files(self)[source]
+

Ensures that all files required for dfnTrans run are in the current directory

+
+
Parameters:
+

self (object) – DFN Class

+
+
Return type:
+

None

+
+
+

Notes

+

None

+
+ +
+
+copy_dfn_trans_files(self)[source]
+

Creates symlink to dfnTrans Execuateble and copies input files for dfnTrans into working directory

+
+
Parameters:
+

self (object) – DFN Class

+
+
Return type:
+

None

+
+
+
+ +
+ +

Create symlinks to files required to run dfnTrans that are in another directory.

+
+
Parameters:
+
    +
  • self (object) – DFN Class

  • +
  • path (string) – Absolute path to primary directory.

  • +
+
+
Return type:
+

None

+
+
+

Notes

+

Typically, the path is DFN.path, which is set by the command line argument -path

+
+ +
+
+dfn_trans(self)[source]
+

Primary driver for dfnTrans.

+
+
Parameters:
+

self (object) – DFN Class

+
+
Return type:
+

None

+
+
+
+ +
+
+run_dfn_trans(self)[source]
+

Execute dfnTrans

+
+
Parameters:
+

self (object) – DFN Class

+
+
Return type:
+

None

+
+
+
+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/pydfnWorks-well.html b/Documentation/sphinx-docs/build/html/pydfnWorks-well.html new file mode 100644 index 000000000..95781a910 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/pydfnWorks-well.html @@ -0,0 +1,267 @@ + + + + + + + pydfnworks: Well Package — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

pydfnworks: Well Package

+

DFN Class functions used for well package

+
+

dfnWorks - Well Package

+
+
+cleanup_wells(self, wells)[source]
+

Moves working files created while making wells into well_data directory

+
+
Parameters:
+
    +
  • self (object) – DFN Class

  • +
  • well

    dictionary of information about the well. Contains the following:

    +
    +
    well[“name”]string

    name of the well

    +
    +
    well[“filename”]string
    +
    filename of the well coordinates. “well_coords.dat” for example.

    Format is : +x0 y0 z0 +x1 y1 z1 +… +xn yn zn

    +
    +
    +
    +
    well[“r”]float

    radius of the well

    +
    +
    +

  • +
+
+
Return type:
+

None

+
+
+

Notes

+

Wells can be a list of well dictionaries

+
+ +
+
+combine_well_boundary_zones(self, wells)[source]
+

Processes zone files for particle tracking. All zone files are combined into allboundaries.zone

+
+
Parameters:
+

None

+
+
Return type:
+

None

+
+
+

Notes

+

None

+
+ +
+
+find_well_intersection_points(self, wells)[source]
+

Identifies points on a DFN where the well intersects the network. +These points are used in meshing the network to have higher resolution in the mesh in these points. +Calls a sub-routine run_find_well_intersection_points.

+
+
Parameters:
+
    +
  • self (object) – DFN Class

  • +
  • well

    dictionary of information about the well. Contains the following:

    +
    +
    well[“name”]string

    name of the well

    +
    +
    well[“filename”]string
    +
    filename of the well coordinates. “well_coords.dat” for example.

    Format is : +x0 y0 z0 +x1 y1 z1 +… +xn yn zn

    +
    +
    +
    +
    well[“r”]float

    radius of the well

    +
    +
    +

  • +
+
+
Return type:
+

None

+
+
+

Notes

+

Wells can be a list of well dictionaries. +Calls the subroutine run_find_well_intersection_points to remove redundant code.

+
+ +
+
+tag_well_in_mesh(self, wells)[source]
+

Identifies nodes in a DFN for nodes the intersect a well with radius r [m]

+
    +
  1. Well coordinates in well[“filename”] are converted to a polyline that are written into “well_{well[‘name’]}_line.inp”

  2. +
  3. Well is expanded to a volume with radius well[“r”] and written into the avs file well_{well[“name”]}_volume.inp

  4. +
  5. Nodes in the DFN that intersect with the well are written into the zone file well_{well[“name”]}.zone

  6. +
  7. If using PFLOTRAN, then an ex file is created from the well zone file

  8. +
+
+
Parameters:
+
    +
  • self (object) – DFN Class

  • +
  • well

    Dictionary of information about the well that contains the following attributes

    +
    +
    well[“name”]string

    name of the well

    +
    +
    well[“filename”]string

    filename of the well coordinates with the following format +x0 y0 z0

    +

    x1 y1 z1

    +

    +

    xn yn zn

    +
    +
    +

  • +
+
+
Return type:
+

None

+
+
+

Notes

+

Wells can be a list of well dictionaries

+
+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/pydfnworks.html b/Documentation/sphinx-docs/build/html/pydfnworks.html new file mode 100644 index 000000000..dc500d2dc --- /dev/null +++ b/Documentation/sphinx-docs/build/html/pydfnworks.html @@ -0,0 +1,327 @@ + + + + + + + pydfnworks: the dfnWorks python package — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

pydfnworks: the dfnWorks python package

+

The pydfnworks package allows the user to run dfnWorks from the command line and call dfnWorks within other python scripts. Because pydfnworks is a package, users can call individual methods from the package.

+

pydfnworks must be installed by the user prior to running dfnworks (pydfnWorks install)

+
+

Running dfnWorks from the command line using pydfnWorks

+

The recommended way to run dfnWorks is using a python call on the command line, or running the script in your favorite IDE.

+
$ python driver.py
+
+
+

The script driver.py is the python control file that contains the workflow of the particular simulation. Below is a basic example taken from the 4_user_rects_example example:

+
from pydfnworks import *
+import os
+
+src_path = os.getcwd()
+jobname = src_path + "/output"
+dfnFlow_file = src_path+ '/dfn_explicit.in'
+dfnTrans_file = src_path + '/PTDFN_control.dat'
+
+DFN = DFNWORKS(jobname,
+               dfnFlow_file=dfnFlow_file,
+               dfnTrans_file=dfnTrans_file,
+               ncpu=8)
+
+DFN.params['domainSize']['value'] = [1.0, 1.0, 1.0]
+DFN.params['h']['value'] = 0.050
+
+DFN.add_user_fract(shape='rect',
+                   radii=0.6,
+                   translation=[-0.4, 0, 0],
+                   normal_vector=[0, 0, 1],
+                   permeability=1.0e-12)
+
+DFN.add_user_fract(shape='rect',
+                   radii=1.0,
+                   aspect_ratio=.65,
+                   translation=[0, 0, 0],
+                   normal_vector=[1, 0, 0],
+                   permeability=1.0e-12)
+
+DFN.add_user_fract(shape='rect',
+                   radii=.6,
+                   translation=[0.4, 0, 0.2],
+                   normal_vector=[0, 0, 1],
+                   permeability=2.0e-12)
+
+DFN.add_user_fract(shape='rect',
+                   radii=.6,
+                   translation=[0.4, 0, -0.2],
+                   normal_vector=[0, 0, 1],
+                   permeability=1.0e-12)
+
+DFN.make_working_directory(delete=True)
+DFN.check_input()
+DFN.print_domain_parameters()
+
+DFN.create_network()
+DFN.mesh_network()
+
+DFN.dfn_flow()
+DFN.dfn_trans()
+
+
+
+
+

The DFNWORKS class

+

Within the python script, a DFN (discrete fracture network) object is created to control the model workflow. Data and model functions are stored on this object, allowing the user to both access information about the DFN while debugging, as well as call functions for modelling everything from network generation to transport modelling. Arguments for creating the DFN object are listed below. Additional arguments and functions required to create the DFN are discussed in other sections of this manual.

+

Default Arguments:

+
from pydfnworks import *
+
+DFN = DFNWORKS(jobname = None, #required
+               ncpu = 4,
+               dfnGen_file = None, #automatically generated
+               dfnFlow_file = None, #required for DFN.dfn_flow()
+               dfnTrans_file = None, #required for DFN.dfn_trans()
+               path = None,
+               prune_file = None,
+               flow_solver = 'PFLOTRAN',
+               inp_file = 'full_mesh.inp',
+               uge_file = 'full_mesh.uge',
+               mat_file = 'materialid.dat',
+               stor_file = None,
+               vtk_file = None,
+               num_nodes = None,
+               mesh_type = 'dfn',
+               cell_based_aperture = False)
+
+
+
+

jobname

+

Description: (Mandatory) Path of the simulation directory. Must be a valid path. The path is stored in DFN.jobname of the DFN object

+

Type: string

+

Example:

+
import os
+src_path = os.getcwd()
+jobname = src_path + "/output"
+
+
+
+
+

ncpu

+

Description: Number of processors to be used in the simulation. Stored as DFN.ncpu.

+

Type: integer

+

Example:

+
ncpu = 8
+
+
+
+
+

dfnFlow_file/dfnGen_file/dfnTrans_file

+
+

Note

+

dfnGen_file is depreciated, file name is automatically specified

+
+

Description: (Mandatory) Path of the input file containing run files for dfnGen, dfnFlow (PFLOTRAN/FEHM/AMANZI), and dfnTrans. This file is parsed and the paths contained within are stored as DFN.dfnGen_file, DFN.dfnFlow_file, and DFN.dfnTrans_file. The local path for the files (string after the final / are stored as DFN.local_dfnGen_file, DFN.local_dfnFlow_file, and DFN.local_dfnTrans_file.

+

Type: string

+

Example:

+
dfnGen_file = 'gen_4_user_rectangles.dat'
+dfnFlow_file = 'dfn_explicit.in'
+dfnTrans_file = 'PTDFN_control.dat'
+
+
+
+
+

path

+

Description: Path to parent directory. Useful for multiple runs using the same network with different meshing techniques, hydraulic properties, flow simulations, or pruned networks. Path is stored as DFN.path.

+

Type: string

+

Example:

+
path = '/dfnWorks/work/4_user_rects_example'
+
+
+
+
+

prune_file

+

Description: Path to ascii file of fractures to be retained (not removed) in the network after pruning. See the pruning example for a workflow demonstration.

+

Type: string

+

Example:

+
prune_file = '/dfnWorks/work/pruning_example/2_core.dat'
+
+
+
+

Note

+

To prune the network, include DFN.mesh_network(prune=True) in the python run file.

+
+
+
+

flow_solver

+

Description: Either ‘PFLOTRAN’ or ‘FEHM’

+

Example:

+
flow_solver = 'PFLOTRAN'
+
+
+
+
+

cell_based_aperture

+

Description: Toggle if the fracture apertures are cell based. If the option is included, then the workflow will assign cell-based apertures and permeabilities from the files aper_node.dat and perm_node.dat. These files consist of two columns, with a single line header value. The first column is the node number. The second column is the aperture/permeability value. See the See the in_fracture_var example for a workflow demonstration.

+

Type: Boolean

+

Example:

+
cell_based_aperture = True
+
+
+
+
+

additional arguments

+

Descriptions: additional arguments that have not been described here will likely not be changed by the user.

+
+
+
+

pydfnWorks : Modules

+

Information about the various pieces of pydfnworks is found in

+

pydfnGen - Network generation, meshing, and analysis

+

pydfnFlow - Flow simulations using PFLOTRAN and FEHM

+

pydfnTrans - Particle Tracking

+

pydfnGraph - Graph-based analysis and pipe-network simulations

+

Well-Package - Well simulations

+
+

Note

+

There are additional required arguments for network generation described in dfnGen

+
+
+
+

Detailed Doxygen Documentation

+

Doxygen

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/search.html b/Documentation/sphinx-docs/build/html/search.html new file mode 100644 index 000000000..e6ab79ab9 --- /dev/null +++ b/Documentation/sphinx-docs/build/html/search.html @@ -0,0 +1,140 @@ + + + + + + Search — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + + + +
+ +
+ +
+
+
+ +
+ +
+

© Copyright 2020, LANL, LA-UR-17-22216.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/searchindex.js b/Documentation/sphinx-docs/build/html/searchindex.js new file mode 100644 index 000000000..eff99ee1b --- /dev/null +++ b/Documentation/sphinx-docs/build/html/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"alltitles": {"4_user_defined_ell_uniform": [[4, "user-defined-ell-uniform"]], "4_user_defined_rects": [[4, "user-defined-rects"]], "About this manual": [[7, "about-this-manual"]], "Adding Fracture Families": [[11, "adding-fracture-families"]], "Adding User Fractures": [[11, "adding-user-fractures"]], "Adding User Fractures From a File": [[11, "adding-user-fractures-from-a-file"]], "Additional Information on the Modification of Hydraulic Properties of the DFN": [[11, "additional-information-on-the-modification-of-hydraulic-properties-of-the-dfn"]], "Analysis of Generated DFN": [[11, "module-pydfnworks.dfnGen.generation.output_report.gen_output"]], "AngleOption (User Defined Fracture)": [[2, "angleoption-user-defined-fracture"]], "Aspect_Ratio": [[2, "aspect-ratio"]], "Authors": [[11, "authors"]], "Beta": [[2, "beta"]], "CMake": [[16, "cmake"]], "Carbon dioxide sequestration": [[0, "carbon-dioxide-sequestration"]], "Citing dfnWorks": [[7, "citing-dfnworks"]], "Clone the dnfWorks repository": [[16, "clone-the-dnfworks-repository"]], "Contact": [[7, "contact"]], "Contributors": [[7, "contributors"]], "Coordinates": [[2, "coordinates"]], "Copyright Information": [[7, "copyright-information"]], "Creating a conforming DFM mesh DFN": [[11, "module-pydfnworks.dfnGen.meshing.dfm.mesh_dfm"]], "Creating an upscaled mesh of the DFN (UDFM)": [[11, "module-pydfnworks.dfnGen.meshing.udfm.map2continuum"]], "DFM": [[11, "dfm"]], "Detailed Doxygen Documentation": [[15, "detailed-doxygen-documentation"]], "Dip_Strike": [[2, "dip-strike"]], "Docker": [[16, "docker"]], "Documentation": [[3, "documentation"]], "Domain Parameters": [[2, "domain-parameters"]], "EllByCoord_Input_File_Path": [[2, "ellbycoord-input-file-path"]], "Ellipse By Coordinate Example": [[2, "ellipse-by-coordinate-example"]], "Ellipse: Constant": [[2, "ellipse-constant"]], "Ellipse: Dip & Strike": [[2, "ellipse-dip-strike"]], "Ellipse: Exponential Distribution": [[2, "ellipse-exponential-distribution"]], "Ellipse: Fracture Orientation": [[2, "ellipse-fracture-orientation"]], "Ellipse: Fracture Radius Distributions": [[2, "ellipse-fracture-radius-distributions"]], "Ellipse: General Parameters": [[2, "ellipse-general-parameters"]], "Ellipse: In Plane Rotation": [[2, "ellipse-in-plane-rotation"]], "Ellipse: Lognormal Distribution": [[2, "ellipse-lognormal-distribution"]], "Ellipse: Spherical Coordinates": [[2, "ellipse-spherical-coordinates"]], "Ellipse: Trend & Plunge": [[2, "ellipse-trend-plunge"]], "Ellipse: Truncated Powerlaw Distribution": [[2, "ellipse-truncated-powerlaw-distribution"]], "Example Applications": [[0, "example-applications"]], "Examples": [[4, "examples"]], "External": [[7, "external"]], "FEHM": [[16, "fehm"]], "Fix paths in test directory": [[16, "fix-paths-in-test-directory"]], "Fracture Family Generation Parameters: Ellipse": [[2, "fracture-family-generation-parameters-ellipse"]], "Fracture Family Generation Parameters: Rectangle": [[2, "fracture-family-generation-parameters-rectangle"]], "General Ellipse Input Example": [[2, "general-ellipse-input-example"]], "General Graph Functions": [[12, "module-pydfnworks.dfnGraph.dfn2graph"]], "General Network Generation Parameters": [[2, "general-network-generation-parameters"]], "General Network Output Parameters": [[2, "general-network-output-parameters"]], "General Rectangle Input Example": [[2, "general-rectangle-input-example"]], "General user defined ellipses parameters": [[2, "general-user-defined-ellipses-parameters"]], "General user defined rectangles parameters": [[2, "general-user-defined-rectangles-parameters"]], "Graph-Based Flow and Transport": [[12, "module-pydfnworks.dfnGraph.graph_flow"]], "Graph-based pruning": [[4, "graph-based-pruning"]], "Installation Requirements for Native Build": [[16, "installation-requirements-for-native-build"]], "Installing pydfnworks": [[16, "installing-pydfnworks"]], "LANL": [[7, "lanl"]], "LaGriT": [[16, "lagrit"]], "LaGrit - Output": [[8, "lagrit-output"]], "Map-DFN upscaling": [[11, "module-pydfnworks.dfnGen.meshing.mapdfn_ecpm.mapdfn_ecpm"]], "Meshing - LaGriT": [[11, "meshing-lagrit"]], "Meshing helper methods": [[11, "module-pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn_helper"]], "Modification of hydraulic properties of the DFN based on background stress field": [[11, "module-pydfnworks.dfnGen.generation.stress"]], "Native build from github repository": [[16, "native-build-from-github-repository"]], "Normal": [[2, "normal"]], "Nuclear waste repository": [[0, "nuclear-waste-repository"]], "Number_of_Vertices": [[2, "number-of-vertices"]], "Obtaining dfnWorks": [[7, "obtaining-dfnworks"]], "Operating Systems": [[16, "operating-systems"]], "PFLOTRAN": [[16, "pflotran"]], "PFLOTRAN - output": [[8, "pflotran-output"]], "Paraview": [[16, "paraview"]], "Polygon file format": [[2, "polygon-file-format"]], "PolygonByCoord_Input_File_Path:": [[2, "polygonbycoord-input-file-path"]], "Polygons": [[2, "polygons"]], "Primary DFN meshing driver": [[11, "module-pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn"]], "Print Parameter Information": [[11, "print-parameter-information"]], "Processing Flow": [[10, "module-pydfnworks.dfnFlow.mass_balance"]], "Processing Generator Input": [[11, "processing-generator-input"]], "Python": [[16, "python"]], "Radii": [[2, "radii"]], "RectByCoord_Input_File_Path": [[2, "rectbycoord-input-file-path"]], "Rectangle By Coordinate Example": [[2, "rectangle-by-coordinate-example"]], "Rectangle: Constant": [[2, "rectangle-constant"]], "Rectangle: Dip & Strike": [[2, "rectangle-dip-strike"]], "Rectangle: Exponential Distribution": [[2, "rectangle-exponential-distribution"]], "Rectangle: Fracture Orientation": [[2, "rectangle-fracture-orientation"]], "Rectangle: Fracture Radius Distributions": [[2, "rectangle-fracture-radius-distributions"]], "Rectangle: General Parameters": [[2, "rectangle-general-parameters"]], "Rectangle: In Plane Rotation": [[2, "rectangle-in-plane-rotation"]], "Rectangle: Lognormal Distribution": [[2, "rectangle-lognormal-distribution"]], "Rectangle: Spherical Coordinates": [[2, "rectangle-spherical-coordinates"]], "Rectangle: Trend & Plunge": [[2, "rectangle-trend-plunge"]], "Rectangle: Truncated Powerlaw Distribution": [[2, "rectangle-truncated-powerlaw-distribution"]], "Run Files": [[8, "run-files"]], "Running Flow : General": [[10, "module-pydfnworks.dfnFlow.flow"]], "Running Flow: FEHM": [[10, "module-pydfnworks.dfnFlow.fehm"]], "Running Flow: PFLOTRAN": [[10, "module-pydfnworks.dfnFlow.pflotran"]], "Running Transport Simulations": [[13, "module-pydfnworks.dfnTrans.transport"]], "Running dfnWorks from the command line using pydfnWorks": [[15, "running-dfnworks-from-the-command-line-using-pydfnworks"]], "Running the Generator": [[11, "module-pydfnworks.dfnGen.generation.generator"]], "Running the dfnWorks container": [[16, "running-the-dfnworks-container"]], "Set the LagriT, PETSC, PFLOTRAN, Python, and FEHM paths": [[16, "set-the-lagrit-petsc-pflotran-python-and-fehm-paths"]], "Setting and Running up dfnWorks": [[16, "setting-and-running-up-dfnworks"]], "Shale energy extraction": [[0, "shale-energy-extraction"]], "Source Code Documentation (Doxygen)": [[2, "source-code-documentation-doxygen"]], "TPL: Truncated Power-Law": [[4, "tpl-truncated-power-law"]], "The DFNWORKS class": [[15, "the-dfnworks-class"]], "Translation": [[2, "translation"]], "Trend_Plunge": [[2, "trend-plunge"]], "UDFM": [[11, "udfm"]], "User Defined Ellipses": [[2, "user-defined-ellipses"]], "User Defined Fracture Generation Parameters": [[2, "user-defined-fracture-generation-parameters"]], "User Defined Rectangles": [[2, "user-defined-rectangles"]], "User defined ellipses by coordinate parameters": [[2, "user-defined-ellipses-by-coordinate-parameters"]], "User defined rectangles by coordinate parameters": [[2, "user-defined-rectangles-by-coordinate-parameters"]], "UserEll_Input_File_Path": [[2, "userell-input-file-path"]], "UserRect_Input_File_Path": [[2, "userrect-input-file-path"]], "Versions": [[7, "versions"]], "Welcome To dfnWorks": [[7, "welcome-to-dfnworks"]], "Welcome to dfnWorks 2.8 documentation!": [[6, "welcome-to-dfnworks-2-8-documentation"]], "additional arguments": [[15, "additional-arguments"]], "angleOption": [[2, "angleoption"]], "boundaryFaces": [[2, "boundaryfaces"]], "cell_based_aperture": [[15, "cell-based-aperture"]], "dfnFlow": [[1, "dfnflow"]], "dfnFlow_file/dfnGen_file/dfnTrans_file": [[15, "dfnflow-file-dfngen-file-dfntrans-file"]], "dfnGen": [[11, "dfngen"]], "dfnGen - C++ Generation Code": [[2, "dfngen-c-generation-code"]], "dfnGen - output": [[8, "dfngen-output"]], "dfnTrans": [[3, "dfntrans"]], "dfnWorks - Well Package": [[14, "module-pydfnworks.dfnGen.well_package.wells"]], "dfnWorks Gallery": [[5, "dfnworks-gallery"]], "dfnWorks Publications": [[9, "dfnworks-publications"]], "disableFram": [[2, "disablefram"]], "domainSize": [[2, "domainsize"]], "domainSizeIncrease": [[2, "domainsizeincrease"]], "eExpMax": [[2, "eexpmax"]], "eExpMean": [[2, "eexpmean"]], "eExpMin": [[2, "eexpmin"]], "eLayer": [[2, "elayer"]], "eLogMax": [[2, "elogmax"]], "eLogMean": [[2, "elogmean"]], "eLogMin": [[2, "elogmin"]], "eRegion": [[2, "eregion"]], "e_p32Targets": [[2, "e-p32targets"]], "ealpha": [[2, "ealpha"]], "easpect": [[2, "easpect"]], "ebeta": [[2, "ebeta"]], "ebetaDistribution": [[2, "ebetadistribution"]], "econst": [[2, "econst"]], "edip": [[2, "edip"]], "edistr": [[2, "edistr"]], "ekappa": [[2, "ekappa"]], "emax": [[2, "emax"]], "emin": [[2, "emin"]], "enumPoints": [[2, "enumpoints"]], "ephi": [[2, "ephi"]], "eplunge": [[2, "eplunge"]], "esd": [[2, "esd"]], "estrike": [[2, "estrike"]], "etheta": [[2, "etheta"]], "etrend": [[2, "etrend"]], "exp: Exponentially Distributed fracture lengths": [[4, "exp-exponentially-distributed-fracture-lengths"]], "famProb": [[2, "famprob"]], "flow_solver": [[15, "flow-solver"]], "forceLargeFractures": [[2, "forcelargefractures"]], "h": [[2, "h"]], "ignoreBoundaryFaces": [[2, "ignoreboundaryfaces"]], "insertUserRectanglesFirst": [[2, "insertuserrectanglesfirst"]], "jobname": [[15, "jobname"]], "keepIsolatedFractures": [[2, "keepisolatedfractures"]], "keepOnlyLargestCluster": [[2, "keeponlylargestcluster"]], "layers": [[2, "layers"]], "nEllipses": [[2, "nellipses"]], "nFamEll": [[2, "nfamell"]], "nFamRect": [[2, "nfamrect"]], "nNodes": [[2, "nnodes"]], "nPoly": [[2, "npoly"]], "nPolygons": [[2, "npolygons"]], "nRectangles": [[2, "nrectangles"]], "nUserEll": [[2, "nuserell"]], "nUserRect": [[2, "nuserrect"]], "ncpu": [[15, "ncpu"]], "numOfLayers": [[2, "numoflayers"]], "numOfRegions": [[2, "numofregions"]], "orientationOption": [[2, "orientationoption"]], "outputAcceptedRadiiPerFamily": [[2, "outputacceptedradiiperfamily"]], "outputAllRadii": [[2, "outputallradii"]], "outputFinalRadiiPerFamily": [[2, "outputfinalradiiperfamily"]], "path": [[15, "path"]], "printRejectReasons": [[2, "printrejectreasons"]], "prune_file": [[15, "prune-file"]], "pydfnWorks : Modules": [[15, "pydfnworks-modules"]], "pydfnworks: Well Package": [[14, "pydfnworks-well-package"]], "pydfnworks: dfnFlow": [[10, "pydfnworks-dfnflow"]], "pydfnworks: dfnGen": [[11, "pydfnworks-dfngen"]], "pydfnworks: dfnGraph": [[12, "pydfnworks-dfngraph"]], "pydfnworks: dfnTrans": [[13, "pydfnworks-dfntrans"]], "pydfnworks: the dfnWorks python package": [[15, "pydfnworks-the-dfnworks-python-package"]], "rExpMax": [[2, "rexpmax"]], "rExpMean": [[2, "rexpmean"]], "rExpMin": [[2, "rexpmin"]], "rLayer": [[2, "rlayer"]], "rLogMax": [[2, "rlogmax"]], "rLogMean": [[2, "rlogmean"]], "rLogMin": [[2, "rlogmin"]], "rRegion": [[2, "rregion"]], "r_p32Targets": [[2, "r-p32targets"]], "radiiListIncrease": [[2, "radiilistincrease"]], "ralpha": [[2, "ralpha"]], "raspect": [[2, "raspect"]], "rbeta": [[2, "rbeta"]], "rbetaDistribution": [[2, "rbetadistribution"]], "rconst": [[2, "rconst"]], "rdip": [[2, "rdip"]], "rdistr": [[2, "rdistr"]], "regions": [[2, "regions"]], "rejectsPerFracture": [[2, "rejectsperfracture"]], "removeFracturesLessThan": [[2, "removefractureslessthan"]], "rkappa": [[2, "rkappa"]], "rmax": [[2, "rmax"]], "rmin": [[2, "rmin"]], "rphi": [[2, "rphi"]], "rplunge": [[2, "rplunge"]], "rsd": [[2, "rsd"]], "rstrike": [[2, "rstrike"]], "rtheta": [[2, "rtheta"]], "rtrend": [[2, "rtrend"]], "seed": [[2, "seed"]], "stopCondition": [[2, "stopcondition"]], "tripleIntersections": [[2, "tripleintersections"]], "userEllByCoord": [[2, "userellbycoord"]], "userEllipsesOnOff": [[2, "userellipsesonoff"]], "userOrientationOption": [[2, "userorientationoption"]], "userPolygonByCoord": [[2, "userpolygonbycoord"]], "userRecByCoord": [[2, "userrecbycoord"]], "userRectanglesOnOff": [[2, "userrectanglesonoff"]], "v2.0": [[7, "v2-0"]], "v2.1": [[7, "v2-1"]], "v2.2": [[7, "v2-2"]], "v2.3": [[7, "v2-3"]], "v2.4": [[7, "v2-4"]], "v2.5": [[7, "v2-5"]], "v2.6": [[7, "v2-6"]], "v2.7": [[7, "v2-7"]], "v2.8 - Current": [[7, "v2-8-current"]], "visualizationMode": [[2, "visualizationmode"]]}, "docnames": ["applications", "dfnflow", "dfngen", "dfntrans", "examples", "gallery", "index_docs", "intro", "output", "publications", "pydfnFlow", "pydfnGen", "pydfnGraph", "pydfnTrans", "pydfnWorks-well", "pydfnworks", "setup"], "envversion": {"sphinx": 61, "sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.viewcode": 1}, "filenames": ["applications.rst", "dfnflow.rst", "dfngen.rst", "dfntrans.rst", "examples.rst", "gallery.rst", "index_docs.rst", "intro.rst", "output.rst", "publications.rst", "pydfnFlow.rst", "pydfnGen.rst", "pydfnGraph.rst", "pydfnTrans.rst", "pydfnWorks-well.rst", "pydfnworks.rst", "setup.rst"], "indexentries": {"add_fracture_source() (in module pydfnworks.dfngraph.dfn2graph)": [[12, "pydfnworks.dfnGraph.dfn2graph.add_fracture_source", false]], "add_fracture_target() (in module pydfnworks.dfngraph.dfn2graph)": [[12, "pydfnworks.dfnGraph.dfn2graph.add_fracture_target", false]], "add_variable_to_mesh() (in module pydfnworks.dfngen.meshing.add_attribute_to_mesh)": [[11, "pydfnworks.dfnGen.meshing.add_attribute_to_mesh.add_variable_to_mesh", false]], "check_dfn_trans_run_files() (in module pydfnworks.dfntrans.transport)": [[13, "pydfnworks.dfnTrans.transport.check_dfn_trans_run_files", false]], "check_false_connections() (in module pydfnworks.dfngen.meshing.udfm.false_connections)": [[11, "pydfnworks.dfnGen.meshing.udfm.false_connections.check_false_connections", false]], "cleanup_wells() (in module pydfnworks.dfngen.well_package.wells)": [[14, "pydfnworks.dfnGen.well_package.wells.cleanup_wells", false]], "combine_well_boundary_zones() (in module pydfnworks.dfngen.well_package.wells)": [[14, "pydfnworks.dfnGen.well_package.wells.combine_well_boundary_zones", false]], "copy_dfn_trans_files() (in module pydfnworks.dfntrans.transport)": [[13, "pydfnworks.dfnTrans.transport.copy_dfn_trans_files", false]], "correct_stor_file() (in module pydfnworks.dfnflow.fehm)": [[10, "pydfnworks.dfnFlow.fehm.correct_stor_file", false]], "create_dfn_flow_links() (in module pydfnworks.dfnflow.flow)": [[10, "pydfnworks.dfnFlow.flow.create_dfn_flow_links", false]], "create_dfn_trans_links() (in module pydfnworks.dfntrans.transport)": [[13, "pydfnworks.dfnTrans.transport.create_dfn_trans_links", false]], "create_graph() (in module pydfnworks.dfngraph.dfn2graph)": [[12, "pydfnworks.dfnGraph.dfn2graph.create_graph", false]], "create_mesh_links() (in module pydfnworks.dfngen.meshing.mesh_dfn.mesh_dfn_helper)": [[11, "pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn_helper.create_mesh_links", false]], "create_network() (in module pydfnworks.dfngen.generation.generator)": [[11, "pydfnworks.dfnGen.generation.generator.create_network", false]], "dfn_flow() (in module pydfnworks.dfnflow.flow)": [[10, "pydfnworks.dfnFlow.flow.dfn_flow", false]], "dfn_gen() (in module pydfnworks.dfngen.generation.generator)": [[11, "pydfnworks.dfnGen.generation.generator.dfn_gen", false]], "dfn_trans() (in module pydfnworks.dfntrans.transport)": [[13, "pydfnworks.dfnTrans.transport.dfn_trans", false]], "dump_fractures() (in module pydfnworks.dfngraph.dfn2graph)": [[12, "pydfnworks.dfnGraph.dfn2graph.dump_fractures", false]], "dump_json_graph() (in module pydfnworks.dfngraph.dfn2graph)": [[12, "pydfnworks.dfnGraph.dfn2graph.dump_json_graph", false]], "effective_perm() (in module pydfnworks.dfnflow.mass_balance)": [[10, "pydfnworks.dfnFlow.mass_balance.effective_perm", false]], "false_connections.py": [[11, "module-false_connections.py", false]], "fehm() (in module pydfnworks.dfnflow.fehm)": [[10, "pydfnworks.dfnFlow.fehm.fehm", false]], "find_well_intersection_points() (in module pydfnworks.dfngen.well_package.wells)": [[14, "pydfnworks.dfnGen.well_package.wells.find_well_intersection_points", false]], "grab_polygon_data() (in module pydfnworks.dfngen.generation.generator)": [[11, "pydfnworks.dfnGen.generation.generator.grab_polygon_data", false]], "graph_transport.py": [[12, "module-graph_transport.py", false]], "greedy_edge_disjoint() (in module pydfnworks.dfngraph.pruning)": [[12, "pydfnworks.dfnGraph.pruning.greedy_edge_disjoint", false]], "inp2gmv() (in module pydfnworks.dfngen.meshing.mesh_dfn.mesh_dfn_helper)": [[11, "pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn_helper.inp2gmv", false]], "inp2vtk_python() (in module pydfnworks.dfngen.meshing.mesh_dfn.mesh_dfn_helper)": [[11, "pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn_helper.inp2vtk_python", false]], "k_shortest_paths_backbone() (in module pydfnworks.dfngraph.pruning)": [[12, "pydfnworks.dfnGraph.pruning.k_shortest_paths_backbone", false]], "lagrit2pflotran() (in module pydfnworks.dfnflow.pflotran)": [[10, "pydfnworks.dfnFlow.pflotran.lagrit2pflotran", false]], "load_json_graph() (in module pydfnworks.dfngraph.dfn2graph)": [[12, "pydfnworks.dfnGraph.dfn2graph.load_json_graph", false]], "make_working_directory() (in module pydfnworks.dfngen.generation.generator)": [[11, "pydfnworks.dfnGen.generation.generator.make_working_directory", false]], "map2continuum.py": [[11, "module-map2continuum.py", false]], "map_to_continuum() (in module pydfnworks.dfngen.meshing.udfm.map2continuum)": [[11, "pydfnworks.dfnGen.meshing.udfm.map2continuum.map_to_continuum", false]], "mapdfn_ecpm() (in module pydfnworks.dfngen.meshing.mapdfn_ecpm.mapdfn_ecpm)": [[11, "pydfnworks.dfnGen.meshing.mapdfn_ecpm.mapdfn_ecpm.mapdfn_ecpm", false]], "mesh_dfm() (in module pydfnworks.dfngen.meshing.dfm.mesh_dfm)": [[11, "pydfnworks.dfnGen.meshing.dfm.mesh_dfm.mesh_dfm", false]], "mesh_dfm.py": [[11, "module-mesh_dfm.py", false]], "mesh_dfn.py": [[11, "module-mesh_dfn.py", false]], "mesh_dfn_helper.py": [[11, "module-mesh_dfn_helper.py", false]], "mesh_network() (in module pydfnworks.dfngen.meshing.mesh_dfn.mesh_dfn)": [[11, "pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn.mesh_network", false]], "module": [[10, "module-pydfnworks.dfnFlow.fehm", false], [10, "module-pydfnworks.dfnFlow.flow", false], [10, "module-pydfnworks.dfnFlow.mass_balance", false], [10, "module-pydfnworks.dfnFlow.pflotran", false], [11, "module-false_connections.py", false], [11, "module-map2continuum.py", false], [11, "module-mesh_dfm.py", false], [11, "module-mesh_dfn.py", false], [11, "module-mesh_dfn_helper.py", false], [11, "module-pydfnworks.dfnGen.generation.generator", false], [11, "module-pydfnworks.dfnGen.generation.input_checking", false], [11, "module-pydfnworks.dfnGen.generation.input_checking.user_defined_fracture_functions", false], [11, "module-pydfnworks.dfnGen.generation.output_report.gen_output", false], [11, "module-pydfnworks.dfnGen.generation.stress", false], [11, "module-pydfnworks.dfnGen.meshing.add_attribute_to_mesh", false], [11, "module-pydfnworks.dfnGen.meshing.dfm.mesh_dfm", false], [11, "module-pydfnworks.dfnGen.meshing.mapdfn_ecpm.mapdfn_ecpm", false], [11, "module-pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn", false], [11, "module-pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn_helper", false], [11, "module-pydfnworks.dfnGen.meshing.udfm.false_connections", false], [11, "module-pydfnworks.dfnGen.meshing.udfm.map2continuum", false], [11, "module-pydfnworks.dfnGen.meshing.udfm.upscale", false], [11, "module-upscale.py", false], [12, "module-graph_transport.py", false], [12, "module-pydfnworks.dfnGraph.dfn2graph", false], [12, "module-pydfnworks.dfnGraph.graph_flow", false], [12, "module-pydfnworks.dfnGraph.graph_transport", false], [12, "module-pydfnworks.dfnGraph.pruning", false], [13, "module-pydfnworks.dfnTrans.transport", false], [14, "module-pydfnworks.dfnGen.well_package.wells", false]], "output_report() (in module pydfnworks.dfngen.generation.output_report.gen_output)": [[11, "pydfnworks.dfnGen.generation.output_report.gen_output.output_report", false]], "parse_pflotran_vtk_python() (in module pydfnworks.dfnflow.pflotran)": [[10, "pydfnworks.dfnFlow.pflotran.parse_pflotran_vtk_python", false]], "pflotran() (in module pydfnworks.dfnflow.pflotran)": [[10, "pydfnworks.dfnFlow.pflotran.pflotran", false]], "pflotran_cleanup() (in module pydfnworks.dfnflow.pflotran)": [[10, "pydfnworks.dfnFlow.pflotran.pflotran_cleanup", false]], "plot_graph() (in module pydfnworks.dfngraph.dfn2graph)": [[12, "pydfnworks.dfnGraph.dfn2graph.plot_graph", false]], "print_domain_parameters() (in module pydfnworks.dfngen.generation.input_checking)": [[11, "pydfnworks.dfnGen.generation.input_checking.print_domain_parameters", false]], "print_family_information() (in module pydfnworks.dfngen.generation.input_checking)": [[11, "pydfnworks.dfnGen.generation.input_checking.print_family_information", false]], "print_user_fracture_information() (in module pydfnworks.dfngen.generation.input_checking.user_defined_fracture_functions)": [[11, "pydfnworks.dfnGen.generation.input_checking.user_defined_fracture_functions.print_user_fracture_information", false]], "pydfnworks.dfnflow.fehm": [[10, "module-pydfnworks.dfnFlow.fehm", false]], "pydfnworks.dfnflow.flow": [[10, "module-pydfnworks.dfnFlow.flow", false]], "pydfnworks.dfnflow.mass_balance": [[10, "module-pydfnworks.dfnFlow.mass_balance", false]], "pydfnworks.dfnflow.pflotran": [[10, "module-pydfnworks.dfnFlow.pflotran", false]], "pydfnworks.dfngen.generation.generator": [[11, "module-pydfnworks.dfnGen.generation.generator", false]], "pydfnworks.dfngen.generation.input_checking": [[11, "module-pydfnworks.dfnGen.generation.input_checking", false]], "pydfnworks.dfngen.generation.input_checking.user_defined_fracture_functions": [[11, "module-pydfnworks.dfnGen.generation.input_checking.user_defined_fracture_functions", false]], "pydfnworks.dfngen.generation.output_report.gen_output": [[11, "module-pydfnworks.dfnGen.generation.output_report.gen_output", false]], "pydfnworks.dfngen.generation.stress": [[11, "module-pydfnworks.dfnGen.generation.stress", false]], "pydfnworks.dfngen.meshing.add_attribute_to_mesh": [[11, "module-pydfnworks.dfnGen.meshing.add_attribute_to_mesh", false]], "pydfnworks.dfngen.meshing.dfm.mesh_dfm": [[11, "module-pydfnworks.dfnGen.meshing.dfm.mesh_dfm", false]], "pydfnworks.dfngen.meshing.mapdfn_ecpm.mapdfn_ecpm": [[11, "module-pydfnworks.dfnGen.meshing.mapdfn_ecpm.mapdfn_ecpm", false]], "pydfnworks.dfngen.meshing.mesh_dfn.mesh_dfn": [[11, "module-pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn", false]], "pydfnworks.dfngen.meshing.mesh_dfn.mesh_dfn_helper": [[11, "module-pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn_helper", false]], "pydfnworks.dfngen.meshing.udfm.false_connections": [[11, "module-pydfnworks.dfnGen.meshing.udfm.false_connections", false]], "pydfnworks.dfngen.meshing.udfm.map2continuum": [[11, "module-pydfnworks.dfnGen.meshing.udfm.map2continuum", false]], "pydfnworks.dfngen.meshing.udfm.upscale": [[11, "module-pydfnworks.dfnGen.meshing.udfm.upscale", false]], "pydfnworks.dfngen.well_package.wells": [[14, "module-pydfnworks.dfnGen.well_package.wells", false]], "pydfnworks.dfngraph.dfn2graph": [[12, "module-pydfnworks.dfnGraph.dfn2graph", false]], "pydfnworks.dfngraph.graph_flow": [[12, "module-pydfnworks.dfnGraph.graph_flow", false]], "pydfnworks.dfngraph.graph_transport": [[12, "module-pydfnworks.dfnGraph.graph_transport", false]], "pydfnworks.dfngraph.pruning": [[12, "module-pydfnworks.dfnGraph.pruning", false]], "pydfnworks.dfntrans.transport": [[13, "module-pydfnworks.dfnTrans.transport", false]], "run_dfn_trans() (in module pydfnworks.dfntrans.transport)": [[13, "pydfnworks.dfnTrans.transport.run_dfn_trans", false]], "run_graph_flow() (in module pydfnworks.dfngraph.graph_flow)": [[12, "pydfnworks.dfnGraph.graph_flow.run_graph_flow", false]], "run_graph_transport() (in module pydfnworks.dfngraph.graph_transport)": [[12, "pydfnworks.dfnGraph.graph_transport.run_graph_transport", false]], "run_lagrit_script() (in module pydfnworks.dfngen.meshing.mesh_dfn.mesh_dfn_helper)": [[11, "pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn_helper.run_lagrit_script", false]], "set_flow_solver() (in module pydfnworks.dfnflow.flow)": [[10, "pydfnworks.dfnFlow.flow.set_flow_solver", false]], "stress_based_apertures() (in module pydfnworks.dfngen.generation.stress)": [[11, "pydfnworks.dfnGen.generation.stress.stress_based_apertures", false]], "tag_well_in_mesh() (in module pydfnworks.dfngen.well_package.wells)": [[14, "pydfnworks.dfnGen.well_package.wells.tag_well_in_mesh", false]], "upscale() (in module pydfnworks.dfngen.meshing.udfm.upscale)": [[11, "pydfnworks.dfnGen.meshing.udfm.upscale.upscale", false]], "upscale.py": [[11, "module-upscale.py", false]], "write_perms_and_correct_volumes_areas() (in module pydfnworks.dfnflow.pflotran)": [[10, "pydfnworks.dfnFlow.pflotran.write_perms_and_correct_volumes_areas", false]], "zone2ex() (in module pydfnworks.dfnflow.pflotran)": [[10, "pydfnworks.dfnFlow.pflotran.zone2ex", false]]}, "objects": {"false_connections": [[11, 0, 0, "-", "py"]], "graph_transport": [[12, 0, 0, "-", "py"]], "map2continuum": [[11, 0, 0, "-", "py"]], "mesh_dfm": [[11, 0, 0, "-", "py"]], "mesh_dfn": [[11, 0, 0, "-", "py"]], "mesh_dfn_helper": [[11, 0, 0, "-", "py"]], "pydfnworks.dfnFlow": [[10, 0, 0, "-", "fehm"], [10, 0, 0, "-", "flow"], [10, 0, 0, "-", "mass_balance"], [10, 0, 0, "-", "pflotran"]], "pydfnworks.dfnFlow.fehm": [[10, 1, 1, "", "correct_stor_file"], [10, 1, 1, "", "fehm"]], "pydfnworks.dfnFlow.flow": [[10, 1, 1, "", "create_dfn_flow_links"], [10, 1, 1, "", "dfn_flow"], [10, 1, 1, "", "set_flow_solver"]], "pydfnworks.dfnFlow.mass_balance": [[10, 1, 1, "", "effective_perm"]], "pydfnworks.dfnFlow.pflotran": [[10, 1, 1, "", "lagrit2pflotran"], [10, 1, 1, "", "parse_pflotran_vtk_python"], [10, 1, 1, "", "pflotran"], [10, 1, 1, "", "pflotran_cleanup"], [10, 1, 1, "", "write_perms_and_correct_volumes_areas"], [10, 1, 1, "", "zone2ex"]], "pydfnworks.dfnGen.generation": [[11, 0, 0, "-", "generator"], [11, 0, 0, "-", "input_checking"], [11, 0, 0, "-", "stress"]], "pydfnworks.dfnGen.generation.generator": [[11, 1, 1, "", "create_network"], [11, 1, 1, "", "dfn_gen"], [11, 1, 1, "", "grab_polygon_data"], [11, 1, 1, "", "make_working_directory"]], "pydfnworks.dfnGen.generation.input_checking": [[11, 1, 1, "", "print_domain_parameters"], [11, 1, 1, "", "print_family_information"], [11, 0, 0, "-", "user_defined_fracture_functions"]], "pydfnworks.dfnGen.generation.input_checking.user_defined_fracture_functions": [[11, 1, 1, "", "print_user_fracture_information"]], "pydfnworks.dfnGen.generation.output_report": [[11, 0, 0, "-", "gen_output"]], "pydfnworks.dfnGen.generation.output_report.gen_output": [[11, 1, 1, "", "output_report"]], "pydfnworks.dfnGen.generation.stress": [[11, 1, 1, "", "stress_based_apertures"]], "pydfnworks.dfnGen.meshing": [[11, 0, 0, "-", "add_attribute_to_mesh"]], "pydfnworks.dfnGen.meshing.add_attribute_to_mesh": [[11, 1, 1, "", "add_variable_to_mesh"]], "pydfnworks.dfnGen.meshing.dfm": [[11, 0, 0, "-", "mesh_dfm"]], "pydfnworks.dfnGen.meshing.dfm.mesh_dfm": [[11, 1, 1, "", "mesh_dfm"]], "pydfnworks.dfnGen.meshing.mapdfn_ecpm": [[11, 0, 0, "-", "mapdfn_ecpm"]], "pydfnworks.dfnGen.meshing.mapdfn_ecpm.mapdfn_ecpm": [[11, 1, 1, "", "mapdfn_ecpm"]], "pydfnworks.dfnGen.meshing.mesh_dfn": [[11, 0, 0, "-", "mesh_dfn"], [11, 0, 0, "-", "mesh_dfn_helper"]], "pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn": [[11, 1, 1, "", "mesh_network"]], "pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn_helper": [[11, 1, 1, "", "create_mesh_links"], [11, 1, 1, "", "inp2gmv"], [11, 1, 1, "", "inp2vtk_python"], [11, 1, 1, "", "run_lagrit_script"]], "pydfnworks.dfnGen.meshing.udfm": [[11, 0, 0, "-", "false_connections"], [11, 0, 0, "-", "map2continuum"], [11, 0, 0, "-", "upscale"]], "pydfnworks.dfnGen.meshing.udfm.false_connections": [[11, 1, 1, "", "check_false_connections"]], "pydfnworks.dfnGen.meshing.udfm.map2continuum": [[11, 1, 1, "", "map_to_continuum"]], "pydfnworks.dfnGen.meshing.udfm.upscale": [[11, 1, 1, "", "upscale"]], "pydfnworks.dfnGen.well_package": [[14, 0, 0, "-", "wells"]], "pydfnworks.dfnGen.well_package.wells": [[14, 1, 1, "", "cleanup_wells"], [14, 1, 1, "", "combine_well_boundary_zones"], [14, 1, 1, "", "find_well_intersection_points"], [14, 1, 1, "", "tag_well_in_mesh"]], "pydfnworks.dfnGraph": [[12, 0, 0, "-", "dfn2graph"], [12, 0, 0, "-", "graph_flow"], [12, 0, 0, "-", "graph_transport"], [12, 0, 0, "-", "pruning"]], "pydfnworks.dfnGraph.dfn2graph": [[12, 1, 1, "", "add_fracture_source"], [12, 1, 1, "", "add_fracture_target"], [12, 1, 1, "", "create_graph"], [12, 1, 1, "", "dump_fractures"], [12, 1, 1, "", "dump_json_graph"], [12, 1, 1, "", "load_json_graph"], [12, 1, 1, "", "plot_graph"]], "pydfnworks.dfnGraph.graph_flow": [[12, 1, 1, "", "run_graph_flow"]], "pydfnworks.dfnGraph.graph_transport": [[12, 1, 1, "", "run_graph_transport"]], "pydfnworks.dfnGraph.pruning": [[12, 1, 1, "", "greedy_edge_disjoint"], [12, 1, 1, "", "k_shortest_paths_backbone"]], "pydfnworks.dfnTrans": [[13, 0, 0, "-", "transport"]], "pydfnworks.dfnTrans.transport": [[13, 1, 1, "", "check_dfn_trans_run_files"], [13, 1, 1, "", "copy_dfn_trans_files"], [13, 1, 1, "", "create_dfn_trans_links"], [13, 1, 1, "", "dfn_trans"], [13, 1, 1, "", "run_dfn_trans"]], "upscale": [[11, 0, 0, "-", "py"]]}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "function", "Python function"]}, "objtypes": {"0": "py:module", "1": "py:function"}, "terms": {"": [0, 1, 2, 3, 4, 5, 7, 9, 12], "0": [0, 1, 2, 4, 6, 10, 11, 12, 15], "000": [7, 8], "00089": 12, "001": [4, 8, 11], "003": 11, "00417817281": 2, "00482133497": 2, "01": [0, 1], "01135305297": 2, "01325d6": 1, "013304": 9, "01807341608": 2, "02": 2, "027": 7, "03245087974": 2, "03882643837": 2, "040": 2, "04369954706": 2, "05": [1, 2], "050": 15, "05259419185": 2, "06272440502": 2, "07": 11, "07783735953": 2, "08441961571": 2, "08462835745": 2, "0853427250495": 2, "0912558548": 2, "0e": [11, 15], "1": [0, 1, 2, 6, 10, 11, 12, 15, 16], "10": [0, 1, 2, 7, 11], "100": 2, "1000": 1, "10000000000": 11, "1000th": 2, "10094407568": 2, "102": 0, "10365780918": 2, "10520773081": 2, "10664963232": 2, "10741842947": 2, "10m": 4, "10th": 2, "11": [0, 11], "110": 11, "11160312936": 2, "11169723114": 2, "1123": 3, "1137": 3, "11909954775": 2, "12": [2, 11, 15], "120": 0, "123": 11, "125": [9, 11], "12746635144": 2, "13": [1, 2, 11], "13046740212": 2, "1320": 11, "1334": 11, "14052566974": 2, "14078724661": 2, "14470985076": 2, "14719749191": 2, "15": 2, "1500000": 1, "157": 2, "157462422292": 2, "15m": 4, "16": 2, "164": 2, "169537908304": 2, "17": [2, 7], "1739128129": 2, "17895163585": 2, "18": 11, "18143095055": 2, "19": [3, 7], "19173173493": 2, "192549006049": 2, "19257780773": 2, "19676496723": 2, "19700291895": 2, "1994": 2, "1d0": 1, "1e": 11, "1m": 4, "2": [0, 1, 2, 4, 11, 12, 15, 16], "20": 2, "200": 0, "2002": 0, "2004": 0, "2008": 11, "2011": 0, "2012": 0, "2013": [0, 11], "2014": [1, 2, 9], "2015": [0, 3, 7, 9], "2016": [9, 11], "2017": [9, 12], "2018": [7, 9, 12], "2019": 9, "2020": [9, 11], "2021": 9, "2022": 9, "2023": 11, "20485792137": 2, "20544838483": 2, "207": 4, "20c": 10, "215302589745": 2, "216": 0, "21771261931": 2, "22216": 7, "222868762162": 2, "22305329999": 2, "22497133918": 2, "22589362057": 2, "23": 2, "23286105726": 2, "23685468994": 2, "23742727251": 2, "24": 0, "25": [2, 11], "25224389054": 2, "25820816606": 2, "25d0": 1, "26426496474": 2, "26469088948": 2, "26666449977": 2, "270": 2, "27165416308": 2, "27249031626": 2, "27643915621": 2, "28455866847": 2, "28911258873": 2, "289753327606": 2, "29432736239": 2, "29594241204": 2, "29639431251": 2, "2_core": 15, "2nd": 9, "2pi": 11, "3": [2, 6, 11, 16], "30": 2, "30082072643": 2, "30297907019": 2, "305": 0, "310044679731": 2, "3154355331": 2, "31745142962": 2, "32": 2, "3215018603": 2, "322281059007": 2, "33581920939": 2, "34094328974": 2, "34275683413": 2, "34398137987": 2, "34506895229": 2, "349200223043": 2, "350": 7, "35725325459": 2, "36": 2, "36161304612": 2, "37": 2, "38212753352": 2, "384249987443": 2, "39004354883": 2, "39229757501": 2, "39564264412": 2, "396173810104": 2, "39770554375": 2, "3d": 9, "4": [1, 2, 6, 9, 11, 15], "40": 2, "400000000000": 11, "40228077595": 2, "40616097581": 2, "40633923745": 2, "41898893677": 2, "42069": 2, "42113429321": 2, "42867426252": 2, "42895858094": 2, "43": 0, "43323157864": 2, "44125563949": 2, "44327042469": 2, "44636375172": 2, "45": [2, 11], "4541413343": 2, "45665913893": 2, "45759785589": 2, "45819042638": 2, "4608669326": 2, "46205561432": 2, "47097810869": 2, "47247873318": 2, "475965761662": 2, "47978607543": 2, "48254521057": 2, "483028953749": 2, "4905528176": 2, "499362646346": 2, "49988903618": 2, "4_user_defined_ell_uniform": 6, "4_user_defined_rect": 6, "4_user_el": 2, "4_user_ell_uniform": 2, "4_user_rect": 2, "4_user_rectangl": 4, "4_user_rects_exampl": 15, "5": [1, 2, 3, 4, 6, 11], "50": [0, 2], "500": 0, "50292931657": 2, "50612429324": 2, "50868187563": 2, "50m": 4, "51825209439": 2, "527": 2, "52840001844": 2, "5300049043": 2, "53213764385": 2, "54466008318": 2, "545132019741": 2, "54841054822": 2, "54844410108": 2, "549550927249": 2, "556": 9, "56": 2, "560": 9, "561983329033": 2, "56312416852": 2, "5639802392": 2, "564917036364": 2, "565188057474": 2, "56729801834": 2, "5749811435": 2, "588931258258": 2, "5d0": 1, "5m": 4, "6": [2, 4, 6, 15, 16], "609": 2, "610312831185": 2, "61045433532": 2, "614809755508": 2, "61970921408": 2, "63804581282": 2, "64081751301": 2, "64526675756": 2, "64584005023": 2, "64805531643": 2, "648176891617": 2, "65": 15, "65124788861": 2, "6562865987": 2, "66597219167": 2, "66719739398": 2, "67958113114": 2, "7": [2, 6, 8], "70265907788": 2, "70593999999": 2, "71": 9, "710166484812": 2, "71519798881": 2, "7368040684": 2, "7422671348": 2, "74246641127": 2, "74938298608": 2, "75769541671": 2, "75834169562": 2, "7605": 11, "76296408041": 2, "76351044547": 2, "76600532497": 2, "78": 2, "79": 4, "793278268371": 2, "8": [1, 2, 4, 11, 15], "80010131269": 2, "804792681255": 2, "80872562941": 2, "80909183961": 2, "809628560699": 2, "81351205493": 2, "814183043594": 2, "81778296407": 2, "81903344627": 2, "82257143457": 2, "82821050463": 2, "83562647916": 2, "84": 7, "841071899053": 2, "84566856205": 2, "85177752427": 2, "85778630995": 2, "860529584164": 2, "8645938936": 2, "867130728085": 2, "8673209588": 2, "87": 0, "88": 9, "8844": 11, "88990150472": 2, "89": 2, "89233218cna000001": 7, "89290711889": 2, "89449659536": 2, "89865208954": 2, "9": [1, 2], "90": 2, "903335314403": 2, "91468659533": 2, "91861492809": 2, "9199696155": 2, "922507014307": 2, "92263630123": 2, "93387033715": 2, "94418542615": 2, "94508200102": 2, "96": 9, "962283071202": 2, "96307141873": 2, "9638588789": 2, "968": 0, "968743065242": 2, "972": 0, "97370232204": 2, "98437001886": 2, "992518232701": 2, "99702019362": 2, "A": [0, 2, 7, 9, 11, 12], "AND": 7, "AS": 7, "As": [2, 11], "BE": 7, "BUT": 7, "BY": [2, 7], "Be": 4, "FOR": 7, "For": [0, 2, 11, 16], "Fors": 0, "IF": 7, "IN": 7, "If": [2, 7, 10, 11, 14, 15, 16], "In": [4, 9], "It": [3, 16], "NO": 7, "NOT": 7, "No": 2, "OF": 7, "ON": 7, "OR": 7, "On": [11, 16], "One": [2, 11], "SUCH": 7, "THE": 7, "TO": 7, "The": [0, 2, 3, 4, 6, 7, 8, 9, 11, 16], "Then": [2, 3, 11], "There": [0, 2, 11, 15], "These": [2, 8, 14, 15, 16], "To": [2, 6, 9, 11, 15, 16], "Will": 2, "With": [9, 16], "_dfn_explicit": 8, "_line": 14, "_output_report": 11, "_volum": 14, "_x": 2, "_y": 2, "_z": 2, "a1871": 2, "a1894": 2, "abandon": 0, "abbrevi": 8, "abil": 7, "about": [0, 2, 3, 6, 8, 10, 11, 14, 15], "abov": [2, 7], "absolut": [10, 13, 16], "ac": 9, "accept": [2, 11], "access": [0, 11, 15], "accord": 2, "accordingli": 7, "account": [10, 11], "accuraci": 2, "act": 7, "activ": 2, "acycl": 12, "ad": [2, 6, 7], "add": [2, 7, 10, 11], "add_fracture_famili": 11, "add_fracture_sourc": [6, 12], "add_fracture_target": [6, 12], "add_user_fract": [2, 11, 15], "add_user_fract_from_fil": [2, 11], "add_variable_to_mesh": 11, "addit": [2, 6, 7], "addition": 7, "adjac": 8, "adler": 0, "administr": 7, "adopt": [0, 3, 7], "advanc": 9, "advect": [0, 3, 9], "advis": 7, "after": [2, 11, 15], "against": 11, "agreement": 0, "ahren": 9, "aidan": [7, 11], "aim": 7, "al": [0, 9, 11, 12], "alamo": [7, 16], "aldrich": 9, "algorithm": [0, 2, 3, 4, 7, 9, 12, 16], "align": [0, 4], "alireza": 11, "all": [1, 2, 4, 7, 10, 11, 12, 13, 14, 16], "allboundari": 14, "allow": [0, 3, 11, 15, 16], "allowed_percentag": 11, "along": [0, 2, 4, 5], "alpha": [1, 2, 11], "alreadi": [11, 16], "also": [0, 2, 11, 16], "altern": 16, "alwai": 2, "amanzi": 15, "ambient": 9, "among": 0, "amount": 11, "an": [0, 1, 2, 3, 4, 6, 7, 9, 12, 14, 16], "anaconda": 16, "anaconda3": 16, "analysi": [6, 9, 12, 15], "andrew": 2, "angl": [2, 8, 11], "angle_opt": 11, "angleopt": 6, "ani": [2, 7, 16], "anomal": 9, "anoth": [3, 10, 13], "anthropogen": 0, "aper_fil": 10, "aper_nod": 15, "apertur": [0, 5, 7, 8, 9, 10, 11, 15], "appli": [4, 9, 11], "applic": [6, 7, 9], "approach": [0, 2, 3, 7, 9, 12], "approxim": [0, 4, 7], "aqueou": 9, "aquif": [0, 9], "ar": [0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], "arch": 16, "area": [0, 2, 8, 10, 11], "argpars": 16, "argument": [4, 6, 10, 11, 13], "aric": [7, 9], "aris": [3, 7], "around": [2, 11], "arrai": 11, "articl": 7, "asa": 9, "ascii": [12, 15], "aspect": [2, 11], "aspect_ratio": [11, 15], "assess": 0, "assign": [2, 7, 11, 15], "assocait": 12, "associ": 0, "assum": [7, 10, 11], "assumpt": 11, "atmospher": 0, "attach": 11, "attempt": 8, "attribur": 11, "attribut": [8, 14], "author": 7, "automat": [2, 11, 15, 16], "av": [8, 14], "avail": [7, 16], "awar": 11, "axi": [0, 2, 4], "b": [3, 9, 11], "bachu": 0, "back": [2, 8, 10], "backbon": [9, 12], "background": [0, 6, 7], "baghbanan": 11, "bandi": 11, "base": [0, 2, 6, 7, 8, 9, 10, 15, 16], "basic": 15, "battaglia": 9, "bdist_wheel": 16, "becaus": 15, "becom": 2, "bedrock": 0, "been": [2, 7, 8, 15], "befor": [2, 11, 16], "begin": 2, "behalf": 7, "behavior": 9, "being": [2, 11], "belong": [2, 11], "below": [1, 2, 11, 15], "beta": 11, "beta_distribut": 11, "between": [0, 2, 8, 9, 11, 16], "bf": 2, "bibtex": 7, "bigi": 9, "bin": 16, "binari": [7, 8], "bipartit": [9, 12], "bipartiti": 12, "birdsel": 9, "black": 12, "block": [1, 7, 12], "blue": [4, 12], "boldsymbol": 2, "bolster": 9, "bool": [10, 11, 12], "boolean": [2, 10, 11, 15], "both": [2, 15], "bottleneck": 16, "bottom": [0, 2, 8, 10], "bound": 2, "bound_zon": 8, "boundari": [0, 1, 2, 4, 8, 10, 11, 12], "boundary_cell_area": 10, "boundary_condit": 1, "boundary_fil": 10, "boundary_output": 8, "boundaryfac": 6, "box": 2, "breakthrough": 9, "bridg": 9, "brief": 8, "brine": 0, "bug": 7, "bui": [3, 7, 9], "build": [1, 6], "built": 11, "bulk_por": 11, "busi": 7, "by_coord": 11, "c": [3, 6, 7, 9, 16], "calcul": 11, "calibr": 9, "call": [1, 7, 10, 11, 14, 15], "can": [0, 1, 2, 4, 7, 10, 11, 14, 15, 16], "cannot": 2, "cantu": 9, "cap": 0, "capabl": [0, 2, 7], "caprock": 9, "carbon": 6, "card": [4, 10, 11], "carei": 9, "carl": [7, 9], "carlo": 9, "carneval": 9, "carri": 4, "case": [4, 9], "caus": 7, "cawi": 9, "cc": 7, "cd": 16, "cdot": 2, "cell": [0, 8, 10, 11, 15], "cell_based_apertur": 6, "cell_data": 10, "cell_siz": 11, "cellinfo": [8, 10], "cement": 9, "center": [2, 11], "centriod": 8, "challeng": [2, 3, 9], "chang": [0, 4, 11, 15], "channel": 9, "chapter": 9, "character": 9, "characterist": [1, 9], "characteristic_curv": 1, "check": [2, 7, 11], "check_dfn_trans_run_fil": [6, 13], "check_false_connect": 11, "check_input": [11, 15], "checkpoint": 10, "chemic": 0, "chen": [7, 9], "choic": 11, "circl": 2, "circular": [0, 4], "cite": 6, "clariti": 4, "class": [6, 10, 11, 12, 13, 14, 16], "clean": 11, "cleanup": 11, "cleanup_wel": [6, 14], "clear": 2, "clearli": 7, "climat": 0, "clock": 2, "clockwis": 2, "clone": 6, "cluster": [2, 9], "co": [0, 2, 7], "co2": [0, 9], "coars": 2, "coarsen": 8, "code": [3, 4, 6, 7, 14, 16], "coincid": 16, "collect": 3, "colon": 11, "color": [4, 5, 12], "column": [11, 15], "com": [7, 16], "combin": [7, 14], "combine_well_boundary_zon": [6, 14], "command": [4, 6, 10, 11, 13, 16], "comment": 11, "commun": 2, "compani": 0, "compar": 9, "comparison": 11, "compat": 7, "complet": [2, 11], "complex": 0, "compli": 16, "compos": 5, "compris": 7, "comput": [2, 3, 4, 7, 9, 10, 16], "concaten": 10, "concatent": 8, "concentr": [2, 11], "condit": [0, 1, 4, 7, 8, 10, 12], "confer": 9, "confirm": 4, "conform": [2, 6, 7, 9, 16], "confus": 7, "connect": [2, 8, 9, 11, 12], "consequenti": 7, "conserv": 3, "consider": 0, "consist": [0, 4, 15, 16], "constant": 11, "constraint": 2, "construct": [0, 2], "contact": 6, "contain": [0, 2, 4, 6, 7, 8, 11, 12, 14, 15], "content": [6, 8], "contiain": 8, "continu": 11, "continuum": [9, 11, 16], "contour": 5, "contract": 7, "contribut": 2, "contributor": 6, "control": [0, 3, 12, 15, 16], "control_plan": 12, "conver": 0, "convert": [2, 10, 11, 14], "convert_ug": 8, "convex": 2, "coordin": [1, 11, 14], "copi": [7, 10, 13], "copy_dfn_trans_fil": [6, 13], "copyright": 6, "cor": 11, "core": 4, "correct": [8, 10, 11], "correct_stor_fil": [6, 10], "correct_ug": 10, "correction_factor": 11, "correctli": 4, "correl": [9, 11], "correspond": [2, 4, 8, 10, 11, 12], "counterclockwis": 2, "coupl": 0, "coupler": 1, "cp_filenam": 12, "creat": [0, 1, 2, 4, 6, 7, 8, 10, 12, 13, 14, 15, 16], "create_dfn_flow_link": [6, 10], "create_dfn_trans_link": [6, 13], "create_graph": [6, 12], "create_mesh_link": 11, "create_network": [11, 15], "creation": 2, "criteria": 2, "critic": 11, "critical_shear_displac": 11, "cross": 16, "crystallin": [0, 9], "cube": 0, "cubic": [0, 4], "cuboid": 2, "current": [0, 4, 6, 10, 11, 12, 13, 16], "currier": 9, "curv": [0, 1, 9], "cutoff": 2, "cvetkov": 9, "d": [1, 2, 7, 9, 11], "d0": 1, "d20": 1, "d6": 1, "d8": 1, "damag": 7, "dame": 7, "darci": [3, 10], "darcy_vel_fil": 10, "darcyvel": 10, "darwin": 16, "dat": [2, 4, 8, 10, 11, 14, 15], "data": [0, 7, 9, 11, 15], "dataset": 1, "date": 11, "dave": 9, "dead": [4, 5], "debug": [2, 15, 16], "deck": 1, "declin": 0, "decreas": 0, "deep": 0, "default": [1, 2, 10, 11, 12, 15], "defin": [4, 6, 7, 8, 11], "define_4_user_ellips": 2, "define_4_user_rect": 2, "definit": 2, "degrad": 2, "degre": [2, 11], "dein": 11, "delaunai": [2, 7, 9, 16], "delet": [10, 11, 15], "demonstr": 15, "denot": 2, "densiti": [2, 9, 10], "dentz": 9, "dep": 11, "depart": 7, "depend": 11, "deplet": 0, "depreci": 15, "depth": 0, "deriv": 7, "describ": [2, 8, 15, 16], "descript": [1, 2, 3, 7, 15], "design": 16, "desir": [2, 11, 16], "detail": [0, 1, 2, 3, 6, 7, 8, 10, 11, 12, 16], "determin": [0, 2, 3, 7, 9, 11], "determinist": [0, 2], "develop": [0, 7, 16], "deviat": 2, "dfm": 6, "dfm_mesh": 11, "dfn": [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 13, 14, 15, 16], "dfn2graph": 7, "dfn_explicit": [4, 8, 15], "dfn_flow": [6, 10, 15], "dfn_gen": 11, "dfn_graph": 12, "dfn_output": [2, 8], "dfn_properti": [1, 8], "dfn_tran": [6, 13, 15], "dfnflow": [3, 6, 7, 15], "dfnflow_fil": 6, "dfngen": [3, 6, 7, 15], "dfngen_fil": 6, "dfngen_mesh": 11, "dfngen_output_report": 11, "dfngraph": [6, 7], "dfntran": [2, 6, 7, 15], "dfntrans_fil": 6, "dfnwork": [0, 2, 4, 8, 10, 11], "dfnworks_path": 16, "dfnworksrc": 16, "dictionari": [2, 11, 14], "differ": [2, 9, 11, 15], "differenti": 16, "diffus": [0, 3, 7, 9, 12], "diffusion_coeffici": 1, "dilat": 11, "dilation_angl": 11, "dimens": 8, "dimension": [2, 3, 7, 9, 11, 12], "dioxid": 6, "dip": [7, 11], "dip_strik": 11, "dir_nam": 11, "direct": [2, 4, 7, 10, 12], "directori": [4, 6, 7, 8, 10, 11, 13, 14, 15], "dirichlet": [0, 1, 4], "dirnam": 11, "disablefram": 6, "disc": [2, 7], "disclaim": 7, "disconnect": 9, "discontinu": 9, "discoveri": 9, "discret": [1, 2, 3, 7, 9, 11, 12, 15], "discuss": [2, 15], "disjoint": 12, "disk": 9, "dispers": [2, 3, 9], "displac": [0, 11], "displai": 7, "dispos": 0, "dissolut": 0, "dist": 16, "distanc": 11, "distribtuion": 11, "distribut": [0, 5, 6, 7, 9, 11, 12, 16], "distributionnumb": 2, "divid": 2, "djidjev": 9, "dnfwork": 6, "do": [2, 3, 7, 16], "docker": [6, 7], "dockerhub": 16, "document": [4, 7, 16], "doe": [2, 3, 9, 10, 11], "domain": [0, 4, 6, 7, 8, 11], "domains": [6, 15], "domainsizeincreas": 6, "done": [2, 16], "doubl": [2, 10, 12], "down": 2, "download": [7, 16], "doxygen": [3, 6], "driven": 12, "driver": [2, 6, 13, 15], "dud": 8, "due": [0, 2, 4, 8, 9], "dump": [8, 10, 11, 12], "dump_flag": 12, "dump_fractur": [6, 12], "dump_json_graph": [6, 12], "dump_traj": 12, "dump_vtk": 10, "dure": [0, 2, 9], "dynam": 0, "e": [2, 9, 10, 12], "e2020jb019754": 11, "e2020wr027986": 9, "ea": 9, "each": [0, 2, 3, 4, 8, 11, 12], "earth": [9, 11], "easiest": 16, "easili": 3, "east": 2, "ebeta": 11, "eboundari": 11, "ecpm": [7, 11], "edfm": 11, "edg": [2, 4, 12, 16], "edit": 11, "ees16": [7, 16], "effect": [0, 2, 3, 9, 10, 11], "effective_perm": [6, 10], "effici": [2, 9], "either": [2, 7, 11, 15], "element": [2, 3, 8, 11], "ell": 11, "ellcoord": 2, "ellips": [4, 6, 11], "ellipt": [2, 4], "elsevi": 7, "email": 7, "emerg": 9, "emili": 11, "en": 2, "enabl": 16, "end": [1, 4, 5, 8, 12], "end_subsurfac": 1, "endors": 7, "energi": [6, 7, 9], "enforc": 0, "engin": [9, 11], "ensembl": 9, "ensur": 13, "entir": 2, "entri": 2, "environ": 16, "environment": 16, "equal": 2, "equat": [2, 3, 11, 16], "equival": [9, 11], "ergiamb": 11, "error": [7, 11], "esteban": 9, "estim": 0, "et": [0, 9, 11, 12], "etc": 2, "evalu": 9, "even": [2, 7, 11], "event": 7, "everi": [2, 8], "everyth": 15, "evolut": [0, 9], "ex": [1, 8, 10, 14], "exactli": 4, "examin": 2, "exampl": [1, 6, 7, 11, 14, 15, 16], "exchang": 16, "execuatebl": 13, "execut": [10, 11, 13, 16], "exemplari": 7, "exhaust": 2, "exist": [0, 11], "exit": [4, 11], "exodu": 11, "exp": [2, 6, 11], "exp_mean": 11, "expand": [7, 14], "expans": 2, "expect": [2, 8], "explicit": 1, "explor": 9, "expon": [2, 4], "exponenti": 6, "expos": 16, "express": 7, "extern": 6, "extract": [4, 6], "f": [0, 2, 9, 11], "face": [2, 10], "factor": 11, "fail": [2, 11], "failur": 11, "fals": [2, 10, 11, 12, 15], "false_connect": 11, "famili": [4, 6, 7, 8, 16], "family_": 11, "family_numb": 11, "famprob": 6, "far": 9, "fashion": [3, 7], "faster": [7, 16], "fault": [0, 9], "favorit": 15, "featur": [2, 7, 9, 11], "fehm": [1, 6, 7, 8, 11, 15], "fehm_ex": 16, "few": [4, 11], "fi": 11, "fidel": 9, "field": [0, 3, 5, 6, 7, 9], "file": [1, 4, 6, 10, 12, 13, 14, 15, 16], "filenam": [1, 2, 10, 11, 12, 14], "filepath": 2, "filter": 4, "final": [0, 2, 7, 8, 11, 15, 16], "final_tim": 1, "finalmesh": 8, "find": 12, "find_well_intersection_point": [6, 14], "finit": [3, 7, 12, 16], "first": [0, 2, 4, 9, 11, 12, 15], "fisher": [0, 2, 11], "fit": 7, "fix": [6, 7], "fix_path": 16, "flag": 11, "float": [2, 10, 11, 12, 14], "flow": [0, 1, 2, 3, 4, 6, 7, 9, 11, 15, 16], "flow_condit": 1, "flow_solv": [6, 10], "fluid": [1, 9], "fluid_properti": 1, "fluid_viscos": 12, "flush": 0, "flux": [3, 12], "fmc_filnam": 11, "fo": 11, "focu": 4, "folder": [4, 16], "follow": [0, 2, 4, 5, 7, 9, 11, 14, 16], "footprint": 0, "forc": [2, 10], "forcelargefractur": 6, "forecast": 9, "form": 7, "format": [0, 1, 8, 9, 10, 11, 12, 14, 16], "formul": 0, "forsmark": 0, "fossil": 0, "found": [0, 2, 4, 7, 10, 12, 15, 16], "foundat": 7, "four": [2, 4, 11], "fourth": 11, "fpdf": 16, "frac": 2, "frac_id_fil": 12, "frac_numb": 11, "frack": 0, "fractur": [0, 1, 3, 5, 6, 7, 8, 9, 12, 15, 16], "fracture1": 8, "fracture2": 8, "fracture_numb": 11, "fracture_spac": 12, "fracutr": 11, "fracx": 11, "fram": [2, 7], "framework": [0, 7, 9], "frampton": 9, "frash": 9, "free": [4, 7], "friction": 11, "friction_angl": 11, "from": [0, 2, 3, 6, 7, 8, 9, 10, 12, 14], "from_fil": 11, "front": [8, 10], "fuel": 0, "full": [2, 8, 12], "full_mesh": [2, 4, 8, 15], "full_mesh_viz": 8, "full_mesh_vol_area": [1, 8], "fulli": 0, "function": [1, 2, 4, 6, 7, 8, 10, 11, 13, 14, 15], "fundament": 0, "further": 1, "futur": 11, "g": [2, 9, 10, 12], "ga": [0, 9], "gabl": [2, 3, 7, 9], "galerkin": 3, "galleri": 6, "garth": 9, "gen_4_user_rectangl": 15, "gen_exponential_dist": 4, "gen_output": 11, "gener": [0, 3, 4, 6, 7, 8, 9, 15], "geolog": 0, "geologi": 9, "geophi": 9, "geophys": [9, 11], "geosci": 9, "geoscienc": [3, 7, 9], "geotechn": 11, "get": 16, "getcwd": 15, "git": 16, "github": [4, 6, 7], "given": 12, "glob": 16, "gmv": 11, "gnu": 7, "go": [2, 9, 16], "good": [0, 2, 7], "gov": [7, 10, 11], "govern": 7, "gowri": 9, "grab_polygon_data": 11, "gradient": [0, 4, 8], "granit": 0, "grant": 7, "graph": [5, 6, 7, 9, 15], "graph_flow": 12, "graph_flow_nam": 12, "graph_typ": 12, "graphic": 9, "graviti": 1, "greater": 2, "greatli": 16, "greedi": 12, "greedy_edge_disjoint": [6, 12], "grid": 1, "grid_vtk_fil": 10, "groundwat": [0, 9], "gtild": 12, "guo": 9, "guthri": 9, "h": [0, 6, 7, 8, 9, 10, 11, 12, 15], "h5": [1, 8, 11], "h5origin": 11, "h5py": [11, 16], "ha": [0, 2, 4, 7, 8, 10], "hadgu": 9, "hagberg": [7, 9], "hamann": 9, "han": 9, "hardwir": 11, "hari": [7, 9], "harrod": 7, "hartlei": 0, "have": [2, 4, 8, 10, 14, 15, 16], "hdf5": 12, "header": [12, 15], "height": 2, "help": [2, 16], "helper": 6, "here": [0, 2, 4, 15], "heterogen": 9, "high": [0, 4, 7, 16], "higher": 14, "highli": [7, 16], "highlight": 0, "histori": 9, "hit": 2, "home": 16, "hope": 7, "horizont": 4, "host": [0, 9, 16], "hour": 0, "how": [2, 16], "howev": [0, 2, 3, 7, 16], "html": 11, "http": [1, 2, 4, 7, 10, 11, 16], "hu": 9, "hub": [7, 16], "hunter": 9, "hy_funct": 11, "hy_param": 11, "hy_vari": 11, "hydraul": [0, 5, 6, 7, 9, 15], "hydrocarbon": 0, "hydrogeol": 9, "hydrol": 0, "hydrologi": 9, "hydromechan": 9, "hyman": [0, 2, 7, 9, 11, 12], "hyman2015dfnwork": 7, "hypothet": 9, "i": [0, 1, 2, 3, 4, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], "id": [1, 4, 8, 11, 15], "ident": 11, "identif": 9, "identifi": [4, 8, 9, 12, 14], "ie": 11, "ieee": 9, "ignor": [2, 12], "ignoreboundaryfac": 6, "imag": [4, 12, 16], "impact": [9, 11], "implement": [2, 3, 11, 16], "impli": 7, "implic": [9, 11], "import": [3, 15, 16], "impos": [0, 2], "in_fracture_var": 15, "incident": 7, "includ": [2, 4, 7, 8, 11, 15], "incoper": 2, "incorpor": 3, "increas": [0, 2, 7, 9, 16], "independ": 11, "index": [2, 8, 10, 11], "index_finish": 10, "index_start": 10, "indic": [2, 12], "indirect": 7, "individu": [8, 10, 11, 12, 15], "indivis": 3, "infer": 9, "inflow": [1, 4, 10, 12], "inflow_pressur": 10, "influenc": 9, "inform": [2, 3, 6, 8, 9, 10, 12, 14, 15], "inher": 3, "initi": [0, 1, 2, 8, 12], "initial_condit": 1, "initial_posit": 12, "initial_timestep_s": 1, "inject": [0, 9], "inlet": [4, 12], "inp": [2, 4, 8, 11, 14, 15], "inp2gmv": 11, "inp2vtk_python": [10, 11], "inp_fil": [11, 15], "input": [1, 4, 6, 7, 8, 10, 12, 13, 15], "input_gener": 8, "input_generator_clean": 8, "insert": [2, 4, 11], "insertuserrectanglesfirst": 6, "insight": 9, "instal": [6, 15], "instead": 16, "instruct": 16, "int": [2, 10, 11, 12], "integ": [2, 8, 12, 15], "integr": 11, "intens": [2, 11], "intent": 2, "interact": [0, 3, 7, 9], "interest": 3, "interfac": 7, "intern": [5, 9, 11], "interplai": 9, "interrupt": 7, "intersect": [2, 8, 9, 11, 12, 14, 16], "intersection_list": 8, "intrins": [3, 7], "invers": 9, "investig": 0, "involv": [0, 1], "io": [4, 16], "ipdpsw": 9, "irrevoc": 7, "isol": [2, 4, 8], "itali": 9, "its": [0, 2, 7, 11], "itself": [3, 7], "j": [0, 2, 7, 9, 11], "jan": 1, "jeffrei": [7, 9, 11], "jeremi": 7, "jhyman": 11, "jimenez": 9, "jimen\u00e9z": 9, "jim\u00e9nez": 9, "jing": 11, "job": [4, 11], "jobnam": [6, 11], "johann": 7, "journal": [7, 9, 11], "joyc": 0, "json": 12, "jul": 9, "jw": 9, "k": [9, 11, 12], "k_background": 11, "k_shortest_paths_backbon": [6, 12], "kang": 9, "kappa": [2, 11], "karra": [0, 1, 3, 7, 9], "keep": 2, "keepisolatedfractur": 6, "keeponlylargestclust": 6, "kei": 11, "kelli": 9, "keyword": [2, 11], "kilomet": [0, 7, 9], "kingdom": 0, "klise": 9, "km": 0, "know": 7, "krotz": [7, 9], "kwickli": 9, "l": [0, 2, 3, 7, 9, 11], "la": 7, "label": 2, "laboratori": [7, 11, 16], "lagrangian": [3, 7], "lagrit": [6, 7, 10], "lagrit2pflotran": [6, 10], "lagrit_ex": 16, "lagrit_fil": 11, "lagrit_log": 8, "lambda": 2, "lanl": [1, 6, 10, 11, 16], "lanru": 11, "laptop": 16, "larg": [1, 10, 16], "larger": 2, "largest": 2, "later": [0, 7], "latest": 16, "law": [0, 2, 6, 9, 11], "layer": [6, 11], "ldot": 2, "lead": 2, "leadership": 16, "leak": 0, "learn": 9, "least": [2, 11, 16], "left": [0, 2, 4, 8, 10], "lei": 9, "leitt": 9, "length": [0, 2, 6, 8, 11, 12], "leon": 11, "less": 2, "let": [7, 11], "letter": 9, "level": 11, "lg": 8, "lgi": 8, "liabil": 7, "liabl": 7, "liangchao": 9, "liangtong": 9, "librari": 11, "licens": 7, "like": [2, 15], "limit": [2, 7, 8, 12], "line": [2, 4, 6, 8, 10, 11, 13], "linear": 11, "link": 9, "liquid_pressur": 1, "liquid_residual_satur": 1, "list": [2, 7, 8, 11, 12, 14, 15], "lithospher": 9, "ll": 7, "llc": 7, "llnl": 7, "ln": 2, "lo": [7, 16], "load": 4, "load_json_graph": [6, 12], "local": [3, 15, 16], "local_dfnflow_fil": [10, 15], "local_dfngen_fil": 15, "local_dfntrans_fil": 15, "local_fold": 16, "local_jobname_effective_perm": 10, "locat": [4, 8, 11, 12], "log": [2, 9, 11], "log_": 11, "log_mean": 11, "log_norm": 11, "log_std": 11, "logic": 7, "logx3dgen": 8, "long": 0, "longer": [2, 11], "longitudin": 3, "loop": 10, "loss": 7, "low": [0, 4], "lower": 2, "lukasczyk": 9, "lump_diag_term": 11, "m": [0, 1, 2, 3, 9, 11, 12, 14, 16], "ma": 8, "mac": 16, "machin": [9, 16], "maco": 16, "made": [11, 12], "magnitud": 4, "mai": [7, 11], "main": [0, 2, 9, 11, 16], "maintain": 11, "majella": 9, "make": [2, 7, 11, 14], "make_working_directori": [11, 15], "makedonska": [0, 1, 2, 3, 7, 9], "mallei": 9, "manag": 0, "mandatori": [2, 15], "manual": [1, 6, 15], "map": [0, 6, 7], "map2continuum": 11, "map_to_continuum": 11, "mapdfn": 11, "mapdfn2pflotran": 11, "mapdfn_ecpm": [6, 11], "mari": 9, "mark": [0, 7], "mart\u00ednez": 9, "mart\u0131nez": 9, "mass": [3, 11], "mass_bal": 1, "mass_flowr": 1, "massiv": [7, 16], "mat_fil": 15, "mat_perm": 11, "mat_por": 11, "match": [2, 9], "materi": [1, 4, 7, 8, 9, 11], "material_properti": 1, "materialid": [8, 15], "mathcal": 11, "mathemat": 9, "mathematica": 7, "matplotlib": 16, "matrix": [0, 3, 7, 8, 9, 11, 12], "matrix_diffus": 12, "matrix_on": 11, "matrix_perm": 11, "matrix_poros": [11, 12], "matt": 7, "matter": 2, "matthew": 11, "matz": 9, "max": 2, "max_capillary_pressur": 1, "max_dist": 11, "max_radiu": 11, "max_resolut": 11, "max_resolution_factor": 11, "maxi": 2, "maximum": [2, 4, 11], "maximum_timestep_s": 1, "maxx": 2, "maxz": 2, "mean": [2, 11], "meant": 2, "mechan": [0, 9, 11], "media": [0, 7, 9, 16], "mediacomput": 9, "medium": 11, "meet": 2, "merchant": 7, "merg": 9, "mesa": 9, "mesh": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 14, 15, 16], "mesh_dfm": 11, "mesh_file_in": 11, "mesh_file_out": 11, "mesh_network": [2, 4, 11, 15], "mesh_perm": 11, "mesh_poros": 11, "mesh_typ": 15, "met": [2, 7], "meter": [0, 2, 4, 11], "method": [0, 2, 3, 6, 9, 15], "methodologi": [2, 3, 7], "mgli": 8, "middleton": 9, "might": 4, "migrat": 0, "millimet": 7, "min": 2, "min_b": 11, "min_dist": 11, "min_radiu": 11, "mine": [9, 11], "miner": 0, "mini": 2, "minim": 2, "minimum": [2, 4, 11], "minx": 2, "minz": 2, "mise": [2, 11], "miss": 11, "mitig": 2, "mix": [2, 9], "ml": 9, "mm": 12, "mode": [1, 2, 9, 10, 11], "model": [0, 7, 9, 11, 12, 15], "modif": [6, 7], "modifi": [4, 7], "modul": [2, 6, 7, 11, 16], "moduleauthor": 11, "modulu": 11, "mohd": 9, "mono": 2, "mont": 9, "moor": 9, "more": [2, 7, 11, 12], "moreov": 0, "mount": 16, "mountain": 9, "mourzenko": 0, "move": [11, 14], "mpa": 0, "mu": [2, 11], "mualem_vg_liq": 1, "much": 7, "mudunuru": 9, "multi": [9, 16], "multicompon": 16, "multilevel": 9, "multiphas": [0, 16], "multipl": [0, 2, 10, 15], "multiprocess": 16, "multiscal": [9, 12], "must": [2, 7, 11, 12, 15, 16], "mwesigwa": 9, "n": [0, 2, 3, 7, 9, 11], "name": [2, 7, 10, 11, 12, 14, 15], "nataliia": [1, 7, 9], "nation": [7, 9, 11, 16], "nativ": 6, "natur": [0, 4, 9], "ncpu": [6, 10], "necessari": [0, 11], "need": [1, 2, 11, 16], "neg": [2, 8, 12], "neglig": 7, "neither": 7, "net": 9, "network": [0, 1, 3, 4, 6, 7, 8, 9, 11, 12, 14, 15, 16], "networkx": [4, 12, 16], "nevada": 9, "new": [0, 2, 4, 7, 9, 11], "newlin": 11, "next": [0, 11, 16], "node": [2, 8, 11, 12, 14, 15], "node_bas": 11, "noflow": 0, "non": [0, 2, 3, 8, 9, 12], "none": [2, 10, 11, 12, 13, 14, 15, 16], "nonexclus": 7, "nonlinear": 9, "nor": 7, "normal": [8, 11], "normal_distribut": 2, "normal_vector": [8, 11, 15], "north": [0, 2], "northern": 0, "note": [2, 3, 4, 8, 10, 11, 12, 13, 14, 16], "noth": 11, "notic": 7, "notr": 7, "novel": 9, "now": 7, "np": 11, "nparticl": 12, "npoli": 6, "npolygon": 11, "nuclear": [6, 7, 9], "num_cell_fals": 11, "num_false_connect": 11, "num_nod": 15, "number": [1, 2, 8, 11, 12, 15], "number_of_point": 11, "number_of_vertic": 11, "numer": [2, 3, 9, 12], "numoflay": 6, "numofregion": 6, "numpi": [11, 16], "nx": 11, "ny": 11, "nz": 11, "o": [1, 9, 11, 15, 16], "object": [7, 10, 11, 12, 13, 14, 15], "obtain": [2, 3, 4, 6, 12], "occurr": 2, "octre": [2, 9, 11], "octree_dfn": 11, "off": [2, 11, 12], "oil": 0, "old": 12, "onc": 2, "one": [0, 1, 2, 3, 4, 11, 16], "ones": 0, "onli": [2, 3, 10, 11, 12], "onto": 2, "open": 16, "oper": 7, "opportun": 9, "option": [1, 2, 7, 11, 12, 15, 16], "order": [2, 4], "oregon": 7, "org": [1, 2, 4, 10, 16], "orien": 11, "orient": [0, 6, 7, 11], "orientation_opt": 11, "orientationopt": [6, 11], "origin": [2, 4, 11], "orl": 11, "ornl": 7, "osthu": 9, "other": [3, 7, 11, 15], "otherwis": 7, "our": 16, "out": [4, 7, 8, 10, 11, 12], "outflow": [1, 4, 10, 12], "outflow_pressur": 10, "outlet": 12, "output": [1, 6, 7, 10, 11, 12, 15, 16], "output_dir": 11, "output_fil": 11, "output_nam": 12, "output_report": [2, 11], "outputacceptedradiiperfamili": 6, "outputallradii": 6, "outputfinalradiiperfamili": 6, "outsid": 2, "outx3dgen": 8, "over": [10, 12], "overlaid": 4, "overlap": 2, "overrid": 11, "overwrit": 11, "own": 11, "oxford": 0, "p": [0, 9], "p32": [2, 11], "p_": 2, "pa": [11, 12], "pacala": 0, "packag": [6, 7, 16], "page": [7, 9], "pahut": 9, "paid": 7, "painter": [0, 2, 3, 7, 9], "panda": 9, "parallel": [3, 7, 9, 16], "param": [2, 8, 10, 11, 15], "paramet": [0, 1, 4, 6, 7, 8, 10, 12, 13, 14], "parashar": 9, "paraview": 4, "parent": 15, "pars": 15, "parse_pflotran_vtk_python": [6, 10], "parsed_vtk": [4, 8], "part": 1, "part_": 4, "partial": 16, "particl": [0, 3, 4, 5, 9, 12, 13, 14, 15], "particular": [0, 7, 12, 15], "partime_fil": 12, "partit": 9, "pascal": 10, "passag": [9, 12], "passiv": 3, "past": 11, "path": [2, 6, 7, 9, 10, 11, 12, 13], "pathlin": [3, 4, 5, 7], "pathnam": 16, "pathwai": 9, "pawar": 9, "pboundary_back_n": 8, "pboundary_bottom": 8, "pboundary_front_": 8, "pboundary_left": 10, "pboundary_left_w": [1, 8], "pboundary_right_": [1, 8], "pboundary_top": 8, "pdf": [7, 11], "per": [2, 8], "percentag": [2, 11], "percol": 9, "percu": 9, "perfectli": 11, "perform": [0, 2, 3, 7], "perm": 8, "perm_fehm": 11, "perm_fil": 10, "perm_nod": 15, "permeabilit": 11, "permeability_funct": 1, "permeabl": [0, 1, 8, 9, 10, 11, 15], "permiss": 7, "permit": 7, "petsc": 6, "petsc_arch": 16, "petsc_dir": 16, "pflotran": [0, 1, 4, 6, 7, 11, 14, 15], "pflotran_cleanup": [6, 10], "pflotran_ex": 16, "pham": 9, "phase": 0, "phenomena": 3, "phi": [2, 11, 12], "phil": 9, "phy": 9, "physic": [0, 3, 9, 12], "pi": 2, "pick": 10, "pickl": 11, "piec": 15, "pip": 16, "pipe": [7, 12, 15], "place": [11, 16], "planar": 2, "plane": [10, 12], "platform": 16, "pleas": [1, 7, 11], "plot": 11, "plot_graph": [6, 12], "plung": [7, 11], "png": 12, "pnnl": 7, "pohlmann": 9, "point": [1, 2, 8, 11, 14], "point_data": 10, "poisson": [7, 9], "polgyon": 2, "poli": [8, 11], "poly_info": 8, "polygon": [6, 8, 11], "polylin": 14, "popul": 11, "poros": [1, 11, 12], "porou": [0, 9, 11, 16], "porter": 9, "portion": [10, 11], "porton": 11, "pose": 3, "posit": [2, 11], "possibl": [2, 7], "post": 3, "potenti": 0, "power": [0, 2, 6, 9, 11], "powerlaw": 5, "precipit": 0, "predefin": 2, "predict": [9, 12], "preferenti": 9, "prepar": 7, "prescrib": 2, "present": [2, 4, 11, 16], "preserv": 9, "press": 0, "pressur": [0, 1, 4, 5, 10, 12], "pressure_in": 12, "pressure_out": 12, "prevent": 0, "primari": [6, 9, 10, 12, 13], "princip": 0, "print": [2, 6, 7], "print_al": 11, "print_domain_paramet": [11, 15], "print_family_inform": 11, "print_primal_grid": 1, "print_user_fracture_inform": 11, "printrejectreason": 6, "prior": [2, 4, 7, 15], "probabili": 11, "probabilist": 9, "probabl": [2, 11], "problem": [0, 3, 9], "proce": [4, 11], "procedia": 9, "proceed": 9, "process": [0, 3, 6, 8, 9, 14, 16], "process_model": 1, "processor": 15, "procur": 7, "produc": [2, 7, 8, 11], "product": [0, 7, 9], "profit": 7, "program": [7, 11], "progress": 11, "project": [0, 2], "promot": 7, "prompt": 11, "propag": 9, "properli": 2, "properti": [1, 2, 6, 8, 9, 15], "propos": 0, "provid": [0, 1, 2, 3, 4, 7, 11], "prune": [6, 15], "prune_fil": [6, 11], "pruning_exampl": 15, "pset": 11, "ptdfn_control": 15, "public": [6, 7], "publicli": 7, "publish": 7, "pull": 16, "pump": 9, "purpl": 5, "purpos": [7, 8], "put": [2, 10], "py": [4, 11, 15, 16], "py3": 16, "pydfnflow": 15, "pydfngen": [2, 15], "pydfngraph": 15, "pydfntran": 15, "pydfnwork": [1, 2, 6, 7], "python": [2, 6, 7, 11], "python3": 7, "python_ex": 16, "q": [3, 9], "qualiti": [3, 7], "quan": 7, "quantif": 9, "quantifi": 9, "quantiti": 16, "queri": 9, "question": 7, "queue": 2, "quick": 2, "quiet": 11, "r": [0, 2, 7, 9, 11, 14, 16], "r_0": 2, "r_u": 2, "radian": [2, 11], "radii": [0, 5, 8, 11, 15], "radii_allaccept": 2, "radii_allaccepted_fam_1": 2, "radii_fin": 8, "radii_final_fam_1": 2, "radiilistincreas": 6, "radiu": [0, 6, 11, 14], "rais": 11, "rajaram": 9, "ramif": 0, "random": [2, 7, 9, 11], "rang": 7, "rapid": 9, "rate": [0, 2, 12], "ratio": [2, 11], "re": [0, 2, 9, 16], "reactiv": [0, 3, 7, 9, 16], "read": [2, 12], "realiz": 11, "reason": [2, 8], "recommend": [1, 2, 4, 7, 15, 16], "reconstruct": 3, "rect": [11, 15], "rectangl": [6, 8, 11], "rectangular": [2, 4], "rectcoord": 2, "red": [4, 12], "redistribut": 7, "reduc": [0, 2, 9], "reduced_mesh": [2, 11], "reduct": [9, 12], "redund": 14, "ref": 2, "refer": [1, 2, 11], "reference_pressur": 1, "refin": [9, 11], "refpolygonbycoord_input_file_path": 2, "region": [1, 6, 7, 11], "reject": [2, 7, 8, 9], "rejectsperattempt": 8, "rejectsperfractur": 6, "rel": 10, "relat": [0, 2, 11], "relationship": 11, "releas": 16, "remain": 2, "remov": [2, 4, 8, 11, 12, 14, 15], "remove_old_sourc": 12, "removefractureslessthan": 6, "render": 4, "report": [0, 2, 7, 9, 11], "repositori": [1, 6, 7, 9], "repres": [3, 9, 11], "represent": [2, 3, 4, 5, 7, 9, 11, 12, 16], "reproduc": [2, 4, 7], "request": [2, 12], "requir": [2, 4, 6, 7, 10, 11, 13, 15], "rescal": 8, "research": [9, 11], "reserv": 7, "reservoir": [0, 9], "resolult": 11, "resolut": [4, 9, 10, 11, 14, 16], "resolv": [2, 3], "resour": [0, 9], "resourc": [9, 11], "respect": 2, "respons": [0, 9], "restart": 10, "restart_fil": 10, "restrepo": 9, "result": [2, 8, 11], "retain": [2, 7, 15], "retent": 3, "return": [10, 11, 12, 13, 14], "rev": 9, "review": [0, 9, 12], "richard": 1, "right": [2, 4, 7, 8, 10], "risk": [0, 11], "road": 0, "robust": 9, "rock": [0, 9, 11], "rock_fehm": 11, "role": 9, "romano": 9, "rosi": 11, "rotat": [8, 11], "rotateln": 8, "rougier": 9, "rout": 7, "routin": [11, 14], "row": 8, "rule": 2, "run": [1, 2, 4, 6, 7, 12], "run_dfn_tran": [6, 13], "run_explicit": 4, "run_find_well_intersection_point": 14, "run_graph_flow": [6, 12], "run_graph_transport": [6, 12], "run_lagrit_script": 11, "ryan": 11, "safe": 0, "safeti": 0, "safro": 9, "salin": 0, "same": [2, 4, 11, 15], "sampl": [0, 1, 2, 7, 9, 11], "sand": 11, "sand2018": 11, "sandia": 11, "satish": [1, 7, 9], "satur": 0, "saturation_funct": 1, "save": [2, 11], "scale": [0, 7, 9, 16], "sci": [2, 9], "scienc": [0, 7, 9, 11], "scientif": [7, 9], "scipi": 16, "scott": [7, 9], "screen": [2, 10, 11], "script": [2, 4, 11, 15, 16], "seamless": 7, "search": 9, "second": [2, 4, 11, 15], "section": [2, 4, 8, 11, 15, 16], "secur": [7, 9], "see": [1, 2, 7, 10, 11, 12, 15, 16], "seed": 6, "select": [0, 2], "self": [10, 11, 12, 13, 14], "semi": 11, "semicorrel": 11, "separ": 11, "sequenti": [2, 9], "sequest": 0, "sequestr": [6, 7], "servic": 7, "set": [0, 2, 4, 6, 7, 10, 11, 13], "set_flow_solv": [6, 10], "setup": 16, "shale": [6, 9], "shall": 7, "shape": [2, 11, 15], "shear": 11, "shear_modulu": 11, "shear_stiff": 11, "sherman": [7, 9], "short": 7, "shortest": 12, "should": [2, 7, 10, 11], "shown": [2, 5], "shriram": [7, 9], "shutil": 16, "si": [2, 12], "siam": [2, 9, 12], "side": [0, 2, 4, 8], "sigma": [2, 11], "sigma_mat": 11, "simplest": 4, "simul": [0, 1, 2, 3, 5, 6, 7, 9, 10, 11, 12, 15, 16], "simulation_typ": 1, "sin": 2, "singl": [2, 4, 8, 11, 15], "sinh": 2, "site": [0, 9], "six": 2, "size": [0, 2, 4, 7, 9, 10, 11, 12], "skb": 0, "slope": [4, 11], "slowli": 0, "small": 2, "smaller": 2, "smallest": 2, "so": [3, 4, 7, 16], "soc": 9, "socolow": 0, "softwar": [7, 16], "soil1": 1, "sol": 9, "sole": 9, "solid": [9, 11], "solut": [3, 4, 7, 8, 9, 10, 11], "solv": [0, 3, 12, 16], "solver": [1, 7, 10, 16], "some": [7, 11], "sorption": 3, "sort": [2, 9], "sourc": [0, 6, 7, 10, 11, 12, 13, 14, 16], "source_list": 12, "south": 2, "sovler": 10, "space": [0, 2], "span": 2, "spars": [9, 11, 12], "specfi": 11, "speci": 11, "special": 7, "specif": 7, "specifi": [2, 11, 15], "spectra": 7, "speed": 16, "spent": 0, "sphere": 2, "spring": 9, "sqrt": 2, "squar": 2, "sr": 0, "src": [11, 16], "src_path": [11, 15], "srinivasan": [7, 9], "stabil": 0, "stabl": 9, "stairstep": 11, "standard": 2, "stansberri": 7, "start": [1, 2, 3, 8, 12, 16], "state": [7, 8, 9, 10, 12], "statist": [0, 2, 9], "stauffer": 9, "steadi": [8, 9, 10, 12], "steady_st": 1, "stein": 11, "step": 16, "stiff": 11, "still": [2, 11], "stochast": [2, 4, 7, 9, 11], "stockholm": 0, "stop": [2, 11], "stopcondit": [6, 11], "stor": [8, 10], "stor_fil": 15, "storag": 0, "store": [11, 15], "store_polygon_data": 11, "str": [11, 12], "strata": 1, "strategi": [2, 9], "stratigraphi": 1, "stratograph": 2, "streamlin": 7, "strength": 11, "stress": [6, 7, 9], "stress_based_apertur": 11, "strict": [7, 11], "strike": [7, 11], "string": [2, 10, 11, 12, 13, 14, 15], "structur": 9, "studi": [0, 7, 9, 11], "sub": [4, 14, 16], "subdirectori": [4, 8, 11], "subgraph": 12, "subnetwork": 9, "subprocess": 16, "subroutin": 14, "subset": 0, "substitut": 7, "subsurfac": [0, 1, 7, 9, 16], "subsurface_flow": 1, "subtract": 2, "succeed": 11, "success": 11, "successfulli": 7, "suffer": 3, "suggest": 2, "suit": 7, "suitabl": [7, 16], "summari": [8, 11], "sund": 9, "supercomput": 16, "supercrit": [0, 9], "support": [0, 2, 10, 11, 12], "sure": [4, 11], "surfac": [2, 4], "sustain": 0, "sweden": 0, "swedish": 0, "sweenei": [7, 9, 11], "sy": 16, "symlink": [10, 11, 13], "symposium": 9, "synopsi": 11, "syntax": 11, "system": [0, 9, 11], "t": [2, 9, 11, 12], "tag_well_in_mesh": [6, 14], "take": [10, 11], "taken": 15, "target": [2, 11, 12], "tartarello": 9, "tdrw": [7, 12], "tdrw_flag": 12, "technic": 0, "techniqu": [7, 15], "technologi": 0, "tecplot": 1, "tempor": 0, "temporari": 2, "tensor": 11, "teresa": 11, "term": [0, 7, 11], "termin": 11, "test": [4, 6], "test_output_fil": 4, "tetrahedron": 11, "text": [2, 11], "textur": 9, "th": 11, "than": [2, 7], "thei": [0, 2, 11], "them": [10, 16], "theori": [7, 9], "therein": [10, 12], "theses": 2, "theta": [2, 11], "thi": [0, 1, 2, 4, 6, 8, 10, 11, 15, 16], "third": [2, 11], "thoma": 7, "those": [2, 11], "thovert": 0, "three": [0, 2, 3, 7, 9, 11, 12], "through": [0, 2, 3, 4, 7], "throughout": 16, "thu": 11, "thumb": 2, "ti": 16, "tight": 0, "time": [0, 1, 2, 7, 9, 11, 12], "titl": 7, "toggl": [11, 15], "tool": [7, 16], "toolbox": [7, 16], "top": [0, 2, 8, 10, 11], "topolog": 9, "topologi": [4, 9], "topopah": 9, "tort": 7, "tortuos": [1, 11], "tortuosity_factor": 11, "total": [0, 2, 11, 12], "tpl": [2, 6, 11], "tporton": 11, "tr": 0, "tracer": 3, "track": [3, 4, 9, 12, 14, 15], "traj": 4, "trajectori": [0, 3, 4, 12], "tramsmiss": 11, "tran": 9, "transact": 9, "transform": 0, "transient": [9, 10], "translat": [8, 11, 15], "transmiss": [0, 9, 11], "transport": [0, 2, 3, 4, 6, 7, 9, 11, 15, 16], "transpos": 2, "trap": 0, "travel": 12, "trend": [7, 11], "trend_plung": 11, "tri_fractur": 8, "triad": 7, "triangl": 16, "triangul": [2, 7, 9, 16], "triangular": 11, "tripl": [2, 8], "triple_point": 8, "tripleintersect": 6, "true": [2, 10, 11, 15], "truncat": [0, 5, 6, 9, 11], "tube": 4, "tupl": 11, "turn": [2, 11], "tutori": 7, "twice": 2, "two": [2, 4, 15], "txt": [2, 4, 8, 10, 11], "type": [1, 2, 10, 11, 12, 13, 14, 15], "typic": [0, 10, 13], "u": 7, "ubuntu": 16, "udfm": [2, 6, 9], "ug": [1, 8, 15], "uge_fil": [10, 15], "uncertainti": [9, 11], "unconvent": 9, "under": [0, 1, 7, 9], "underli": 2, "understand": [0, 2, 9], "understood": 0, "undertaken": 0, "uniform": [0, 2, 4, 11, 12], "uniform_mesh": 11, "uniformli": 4, "uniqu": [2, 3], "unit": [0, 2, 10, 11, 12], "univers": [0, 7], "unix": 16, "unless": 2, "unstabl": 2, "unstructur": [1, 3], "unstructured_explicit": 1, "until": 2, "up": [2, 4, 6, 7, 11, 12], "updat": 7, "upper": 2, "uppland": 0, "upscal": [2, 6, 9], "ur": 7, "us": [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16], "usa": 9, "usag": [1, 9, 11], "user": [1, 4, 6, 7, 8, 15], "user_defined_": 11, "user_funct": 8, "user_polygon": 2, "user_rect": 8, "userell_input_filepath": 2, "userellips": 2, "usernam": 16, "userpolygon": 2, "userrectangl": 2, "ushijima": 9, "util": 7, "v": [0, 9, 16], "v2": [6, 11], "v3": 7, "valera": 9, "valid": [2, 15], "valocchi": 9, "valu": [2, 8, 10, 11, 12, 15], "van_genuchten": 1, "vari": 0, "variabl": [1, 5, 9, 11, 16], "variable_fil": 11, "varianc": [2, 11], "variat": 11, "variou": [7, 15], "vassallo": 9, "vec": 2, "vector": [2, 5, 8, 11], "veloc": [3, 4, 5, 10, 12], "verbos": 11, "veri": 16, "version": [6, 11, 16], "version2": 11, "vertex": [2, 4, 12], "vertic": [0, 2, 4, 11], "vi": 16, "via": [2, 9], "viewer": 11, "visit": 16, "visual": [2, 4, 7, 9, 11, 16], "visual_mod": [2, 11], "visualis": 16, "visualizationmod": 6, "visualmod": 8, "viswanathan": [0, 7, 9], "vital": 0, "vladimir": 9, "volum": [2, 3, 7, 8, 10, 14, 16], "volumetr": 12, "von": [2, 11], "voronoi": [11, 16], "vtk": [1, 4, 8, 10, 11, 16], "vtk_file": 15, "w": [2, 3, 7, 9], "wa": [0, 7, 11], "wai": [2, 7, 15, 16], "walk": 7, "wang": 9, "want": [2, 11], "warn": [7, 8, 11], "warningfiledfngen": 8, "warranti": 7, "wast": [6, 7, 9], "water": [0, 9, 10, 11, 12], "we": [0, 3, 4, 7, 11, 16], "wealth": 3, "wedg": 0, "weight": 12, "well": [0, 1, 2, 6, 7, 9, 11, 15, 16], "well_": 14, "well_coord": 14, "well_data": 14, "wenji": 9, "west": 2, "what": [0, 11, 12], "when": [2, 11], "where": [2, 9, 11, 14, 16], "whether": [2, 7, 11], "which": [2, 3, 4, 7, 8, 10, 11, 12, 13, 16], "while": [9, 11, 14, 15, 16], "white": 2, "whl": 16, "whole": [2, 11], "whose": [0, 4, 5], "why": 0, "wiki": 2, "wikipedia": 2, "william": 9, "within": [2, 4, 5, 7, 15], "without": [7, 11], "wood": 2, "woodr": 9, "work": [0, 2, 7, 9, 10, 11, 13, 14, 15, 16], "workflow": [7, 10, 11, 15], "workshop": 9, "workstat": 16, "worldwid": 7, "wrapper": 11, "write": [10, 11, 12], "write_perms_and_correct_volumes_area": [6, 10], "written": [2, 7, 10, 11, 12, 14], "www": [1, 4, 10, 16], "x": [2, 4, 8, 10, 11], "x0": [8, 14], "x1": [2, 8, 11, 14], "x2": [2, 11], "x3": 2, "x4": 2, "x_0": 2, "x_1": 2, "x_n": 2, "xfehm_v3": 16, "xmf": 16, "xn": [2, 11, 14], "xradiu": 2, "xu": 9, "y": [2, 4, 8, 9, 10], "y0": [8, 14], "y1": [2, 8, 11, 14], "y2": [2, 11], "y3": 2, "y4": 2, "y_0": 2, "y_1": 2, "y_n": 2, "year": [0, 7], "yingtao": 9, "yn": [2, 11, 14], "you": [2, 4, 7, 11, 16], "your": [1, 4, 7, 11, 15, 16], "yradiu": 2, "yu": 7, "yunmin": 9, "yusof": 9, "z": [2, 8, 9, 10], "z0": [8, 14], "z1": [2, 8, 11, 14], "z2": [2, 11], "z3": 2, "z4": 2, "z_0": 2, "z_1": 2, "z_n": 2, "zero": [2, 8], "zhan": 9, "zhao": 11, "zhihong": 11, "zhou": 9, "zmax": 2, "zmin": 2, "zn": [2, 11, 14], "zone": [8, 9, 10, 14], "zone2ex": [6, 10], "zone_fil": 10, "zou": 9}, "titles": ["Example Applications", "dfnFlow", "dfnGen - C++ Generation Code", "dfnTrans", "Examples", "dfnWorks Gallery", "Welcome to dfnWorks 2.8 documentation!", "Welcome To dfnWorks", "Run Files", "dfnWorks Publications", "pydfnworks: dfnFlow", "pydfnworks: dfnGen", "pydfnworks: dfnGraph", "pydfnworks: dfnTrans", "pydfnworks: Well Package", "pydfnworks: the dfnWorks python package", "Setting and Running up dfnWorks"], "titleterms": {"0": 7, "1": 7, "2": [6, 7], "3": 7, "4": 7, "4_user_defined_ell_uniform": 4, "4_user_defined_rect": 4, "5": 7, "6": 7, "7": 7, "8": [6, 7], "By": 2, "In": 2, "The": 15, "To": 7, "about": 7, "ad": 11, "addit": [11, 15], "an": 11, "analysi": 11, "angleopt": 2, "applic": 0, "argument": 15, "aspect_ratio": 2, "author": 11, "background": 11, "base": [4, 11, 12], "beta": 2, "boundaryfac": 2, "build": 16, "c": 2, "carbon": 0, "cell_based_apertur": 15, "cite": 7, "class": 15, "clone": 16, "cmake": 16, "code": 2, "command": 15, "conform": 11, "constant": 2, "contact": 7, "contain": 16, "contributor": 7, "coordin": 2, "copyright": 7, "creat": 11, "current": 7, "defin": 2, "detail": 15, "dfm": 11, "dfn": 11, "dfnflow": [1, 10], "dfnflow_fil": 15, "dfngen": [2, 8, 11], "dfngen_fil": 15, "dfngraph": 12, "dfntran": [3, 13], "dfntrans_fil": 15, "dfnwork": [5, 6, 7, 9, 14, 15, 16], "dioxid": 0, "dip": 2, "dip_strik": 2, "directori": 16, "disablefram": 2, "distribut": [2, 4], "dnfwork": 16, "docker": 16, "document": [2, 3, 6, 15], "domain": 2, "domains": 2, "domainsizeincreas": 2, "doxygen": [2, 15], "driver": 11, "e_p32target": 2, "ealpha": 2, "easpect": 2, "ebeta": 2, "ebetadistribut": 2, "econst": 2, "edip": 2, "edistr": 2, "eexpmax": 2, "eexpmean": 2, "eexpmin": 2, "ekappa": 2, "elay": 2, "ellbycoord_input_file_path": 2, "ellips": 2, "elogmax": 2, "elogmean": 2, "elogmin": 2, "emax": 2, "emin": 2, "energi": 0, "enumpoint": 2, "ephi": 2, "eplung": 2, "eregion": 2, "esd": 2, "estrik": 2, "etheta": 2, "etrend": 2, "exampl": [0, 2, 4], "exp": 4, "exponenti": [2, 4], "extern": 7, "extract": 0, "famili": [2, 11], "famprob": 2, "fehm": [10, 16], "field": 11, "file": [2, 8, 11], "fix": 16, "flow": [10, 12], "flow_solv": 15, "forcelargefractur": 2, "format": 2, "fractur": [2, 4, 11], "from": [11, 15, 16], "function": 12, "galleri": 5, "gener": [2, 10, 11, 12], "github": 16, "graph": [4, 12], "h": 2, "helper": 11, "hydraul": 11, "ignoreboundaryfac": 2, "inform": [7, 11], "input": [2, 11], "insertuserrectanglesfirst": 2, "instal": 16, "jobnam": 15, "keepisolatedfractur": 2, "keeponlylargestclust": 2, "lagrit": [8, 11, 16], "lanl": 7, "law": 4, "layer": 2, "length": 4, "line": 15, "lognorm": 2, "manual": 7, "map": 11, "mesh": 11, "method": 11, "modif": 11, "modul": 15, "nativ": 16, "ncpu": 15, "nellips": 2, "network": 2, "nfamel": 2, "nfamrect": 2, "nnode": 2, "normal": 2, "npoli": 2, "npolygon": 2, "nrectangl": 2, "nuclear": 0, "number_of_vertic": 2, "numoflay": 2, "numofregion": 2, "nuserel": 2, "nuserrect": 2, "obtain": 7, "oper": 16, "orient": 2, "orientationopt": 2, "output": [2, 8], "outputacceptedradiiperfamili": 2, "outputallradii": 2, "outputfinalradiiperfamili": 2, "packag": [14, 15], "paramet": [2, 11], "paraview": 16, "path": [15, 16], "petsc": 16, "pflotran": [8, 10, 16], "plane": 2, "plung": 2, "polygon": 2, "polygonbycoord_input_file_path": 2, "power": 4, "powerlaw": 2, "primari": 11, "print": 11, "printrejectreason": 2, "process": [10, 11], "properti": 11, "prune": 4, "prune_fil": 15, "public": 9, "pydfnwork": [10, 11, 12, 13, 14, 15, 16], "python": [15, 16], "r_p32target": 2, "radii": 2, "radiilistincreas": 2, "radiu": 2, "ralpha": 2, "raspect": 2, "rbeta": 2, "rbetadistribut": 2, "rconst": 2, "rdip": 2, "rdistr": 2, "rectangl": 2, "rectbycoord_input_file_path": 2, "region": 2, "rejectsperfractur": 2, "removefractureslessthan": 2, "repositori": [0, 16], "requir": 16, "rexpmax": 2, "rexpmean": 2, "rexpmin": 2, "rkappa": 2, "rlayer": 2, "rlogmax": 2, "rlogmean": 2, "rlogmin": 2, "rmax": 2, "rmin": 2, "rotat": 2, "rphi": 2, "rplung": 2, "rregion": 2, "rsd": 2, "rstrike": 2, "rtheta": 2, "rtrend": 2, "run": [8, 10, 11, 13, 15, 16], "seed": 2, "sequestr": 0, "set": 16, "shale": 0, "simul": 13, "sourc": 2, "spheric": 2, "stopcondit": 2, "stress": 11, "strike": 2, "system": 16, "test": 16, "thi": 7, "tpl": 4, "translat": 2, "transport": [12, 13], "trend": 2, "trend_plung": 2, "tripleintersect": 2, "truncat": [2, 4], "udfm": 11, "up": 16, "upscal": 11, "us": 15, "user": [2, 11], "userell_input_file_path": 2, "userellbycoord": 2, "userellipsesonoff": 2, "userorientationopt": 2, "userpolygonbycoord": 2, "userrecbycoord": 2, "userrect_input_file_path": 2, "userrectanglesonoff": 2, "v2": 7, "version": 7, "visualizationmod": 2, "wast": 0, "welcom": [6, 7], "well": 14}}) \ No newline at end of file diff --git a/Documentation/sphinx-docs/build/html/setup.html b/Documentation/sphinx-docs/build/html/setup.html new file mode 100644 index 000000000..526cdc34b --- /dev/null +++ b/Documentation/sphinx-docs/build/html/setup.html @@ -0,0 +1,301 @@ + + + + + + + Setting and Running up dfnWorks — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Setting and Running up dfnWorks

+
+

Docker

+

The easiest way to get started with dfnWorks is using our docker container (https://hub.docker.com/r/ees16/dfnworks).

+

If you do not already have Docker installed on your machine, +visit Getting Started with Docker.

+

The dfnWorks Docker image can be pulled from DockerHub using:

+
$ docker pull ees16/dfnworks:latest
+
+
+
+

Running the dfnWorks container

+

The base command for running the dfnWorks container is:

+
docker run -ti ees16/dfnworks:latest
+
+
+

However, to exchange files between the host and container, we will need to mount +a volume.

+

The option -v LOCAL_FOLDER:/dfnWorks/work will allow all files present in the +container folder dfnWorks/work to be exposed to LOCAL_FOLDER, where +LOCAL_FOLDER is the absolute path to a folder on your machine.

+

With this is place, the final command for running the Docker container is:

+

On macOS:

+
docker run -ti -v <LOCAL_FOLDER>:/dfnWorks/work ees16/dfnworks:latest
+
+
+
+
+
+

Native build from github repository

+

This document contains instructions for setting up dfnWorks natively on your +machine. To setup dfnWorks using Docker instead, see the next section.

+
+

Clone the dnfWorks repository

+
$ git clone https://github.com/lanl/dfnWorks.git
+
+
+
+
+

Fix paths in test directory

+

Fix the pathnames in files throughout pydfnworks. This can be done automatically by running the script fix_paths.py:

+
$ cd dfnWorks/pydfnworks/bin/
+$ python fix_paths.py
+
+
+
+
+

Set the LagriT, PETSC, PFLOTRAN, Python, and FEHM paths

+

Before executing dfnWorks, the following paths must be set:

+
    +
  • dfnWorks_PATH: the dfnWorks repository folder

  • +
  • PETSC_DIR and PETSC_ARCH: PETSC environmental variables

  • +
  • PFLOTRAN_EXE: Path to PFLOTRAN executable

  • +
  • PYTHON_EXE: Path to python executable

  • +
  • LAGRIT_EXE: Path to LaGriT executable

  • +
+
$ vi dfnWorks/pydfnworks/pydfnworks/paths.py
+
+
+

For example:

+
os.environ['dfnWorks_PATH'] = '/home/username/dfnWorks/'
+
+
+

Alternatively, you can create a .dfnworksrc file in your home directory with the following format

+
{
+    "dfnworks_PATH": "<your-home-directory>/src/dfnworks-main/",
+    "PETSC_DIR": "<your-home-directory>/src/petsc",
+    "PETSC_ARCH": "arch-darwin-c-debug",
+    "PFLOTRAN_EXE": "<your-home-directory>/src/pflotran/src/pflotran/pflotran",
+    "PYTHON_EXE": "<your-home-directory>/anaconda3/bin/python",
+    "LAGRIT_EXE": "<your-home-directory>/bin/lagrit",
+    "FEHM_EXE": "<your-home-directory>//src/xfehm_v3.3.1"
+}
+
+
+
+
+

Installing pydfnworks

+

Go up into the pydfnworks sub-directory:

+
$ cd dfnWorks/pydfnworks/
+
+
+

Complie The pydfnWorks Package:

+
$ python setup.py bdist_wheel
+
+
+

Install on Your Local Machine:

+
$ python -m pip install dist/pydfnworks-2.6-py3-none-any.whl
+
+
+

Note that the python version in dist/ needs to be consistent with the current release

+
+
+

Installation Requirements for Native Build

+

Tools that you will need to run the dfnWorks work flow are described in +this section. VisIt and ParaView, which enable visualization of desired +quantities on the DFNs, are optional, but at least one of them is highly +recommended for visualization. CMake is also optional but allows faster IO +processing using C++.

+
+

Operating Systems

+

dfnWorks currently runs on Macs and Unix machine running Ubuntu.

+
+
+

Python

+

pydfnworks uses Python 3. We recommend using +the Anaconda 3 distribution of Python, available at https://www.continuum.io/. +pydfnworks requires the following python modules: numpy, h5py, scipy, matplotlib, multiprocessing, argparse, shutil, os, sys, networkx, subprocess, glob, networkx, fpdf, and re.

+
+
+

LaGriT

+

The LaGriT meshing toolbox is used to create a high resolution computational +mesh representation of the DFN in parallel. An algorithm for conforming +Delaunay triangulation is implemented so that fracture intersections are +coincident with triangle edges in the mesh and Voronoi control volumes are +suitable for finite volume flow solvers such as FEHM and PFLOTRAN.

+
+
+

PFLOTRAN

+

PFLOTRAN is a massively parallel subsurface flow and reactive transport +code. PFLOTRAN solves a system of partial differential equations for +multiphase, multicomponent and multi-scale reactive flow and transport in +porous media. The code is designed to run on leadership-class supercomputers +as well as workstations and laptops.

+
+
+

FEHM

+

FEHM is a subsurface multiphase flow code developed at Los Alamos National +Laboratory.

+
+
+

CMake

+

CMake is an open-source, cross-platform family of tools designed to build, +test and package software. It is needed to use C++ for processing files at a +bottleneck IO step of dfnWorks. Using C++ for this file processing optional +but can greatly increase the speed of dfnWorks for large fracture networks. +Details on how to use C++ for file processing are in the scripts section of +this documentation.

+
+
+

Paraview

+

Paraview is a parallel, open-source visualisation software. PFLOTRAN can +output in .xmf and .vtk format. These can be imported in Paraview +for visualization. While not required for running dfnWorks, Paraview is +very helpful for visualizing dfnWorks simulations.

+

Instructions for downloading and installing Paraview can be found at +http://www.paraview.org/download/

+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Documentation/sphinx-docs/source/conf.py b/Documentation/sphinx-docs/source/conf.py index 2639deb3c..1e3b44933 100755 --- a/Documentation/sphinx-docs/source/conf.py +++ b/Documentation/sphinx-docs/source/conf.py @@ -16,8 +16,7 @@ # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # -import os -import sys +import os, sys, subprocess, re # sys.path.insert(0, os.path.abspath('.')) sys.path.insert(0, os.path.abspath('/home/username/dfnWorks/pydfnworks/pydfnworks')) @@ -69,11 +68,18 @@ # |version| and |release|, also used in various other places throughout the # built documents. # -# The short X.Y version. -version = u'2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027' +decode = lambda x : x.decode(sys.stdout.encoding) if isinstance(x,bytes) else x -# The full version, including alpha/beta/rc tags. -release = u'2.7' +dfnWorks_branch=decode(subprocess.check_output('git symbolic-ref --short HEAD',shell=True).rstrip()) +dfnWorks_global_id=decode(subprocess.check_output('git rev-parse --short HEAD',shell=True).rstrip()) + +# Use it tag to determine version +dfnWorks_latest_tag=decode(subprocess.check_output('git tag -l \'v*\'', shell=True)).split()[-1].rstrip() +dfnWorks_latest_tag_ver=dfnWorks_latest_tag.replace('v',' ') + +version = dfnWorks_latest_tag_ver + ' LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027' + +release = dfnWorks_latest_tag # The language for content auto-generated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/Documentation/sphinx-docs/source/dfngen_docs/dfngen_domain.inc b/Documentation/sphinx-docs/source/dfngen_docs/dfngen_domain.inc index 381fef4ef..245608cfc 100644 --- a/Documentation/sphinx-docs/source/dfngen_docs/dfngen_domain.inc +++ b/Documentation/sphinx-docs/source/dfngen_docs/dfngen_domain.inc @@ -275,9 +275,9 @@ Type: Value of 0,1,2 This value is set automatically with the definition of fracture families (See :ref:`pydfnGen `). .. note:: - | For spherical coordinates, values are defined using the function parameters :ref:`theta`/:ref:`phi`. - | For Trend/Plunge, values are defined using :ref:`trend`/:ref:`plunge`. - | For Dip/Strike, values are defined using :ref:`dip`/:ref:`strike`. + | For spherical coordinates, values are defined using the function parameters :ref:`theta `/:ref:`phi `. + | For Trend/Plunge, values are defined using :ref:`trend `/:ref:`plunge `. + | For Dip/Strike, values are defined using :ref:`dip `/:ref:`strike `. .. warning:: | When using Trend / Plunge or Dip / Strike, :ref:`angleOption` must be set to degree (default), :ref:`angleOption` = 'degree' diff --git a/docs/_modules/index.html b/docs/_modules/index.html index f93c8af87..b51063b9a 100644 --- a/docs/_modules/index.html +++ b/docs/_modules/index.html @@ -1,19 +1,21 @@ - + - Overview: module code — dfnWorks 2.7 documentation - - + Overview: module code — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/_modules/pydfnworks/dfnFlow/fehm.html b/docs/_modules/pydfnworks/dfnFlow/fehm.html index 805e0dbb3..9f993d749 100644 --- a/docs/_modules/pydfnworks/dfnFlow/fehm.html +++ b/docs/_modules/pydfnworks/dfnFlow/fehm.html @@ -1,19 +1,21 @@ - + - pydfnworks.dfnFlow.fehm — dfnWorks 2.7 documentation - - + pydfnworks.dfnFlow.fehm — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/_modules/pydfnworks/dfnFlow/flow.html b/docs/_modules/pydfnworks/dfnFlow/flow.html index ea432610f..c5688d2ec 100644 --- a/docs/_modules/pydfnworks/dfnFlow/flow.html +++ b/docs/_modules/pydfnworks/dfnFlow/flow.html @@ -1,19 +1,21 @@ - + - pydfnworks.dfnFlow.flow — dfnWorks 2.7 documentation - - + pydfnworks.dfnFlow.flow — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/_modules/pydfnworks/dfnFlow/mass_balance.html b/docs/_modules/pydfnworks/dfnFlow/mass_balance.html index 6f0e8e09f..57946503b 100644 --- a/docs/_modules/pydfnworks/dfnFlow/mass_balance.html +++ b/docs/_modules/pydfnworks/dfnFlow/mass_balance.html @@ -1,19 +1,21 @@ - + - pydfnworks.dfnFlow.mass_balance — dfnWorks 2.7 documentation - - + pydfnworks.dfnFlow.mass_balance — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
@@ -100,143 +102,56 @@

Source code for pydfnworks.dfnFlow.mass_balance

< import numpy as np import glob -__author__ = 'Satish Karra' -__email__ = 'satkarra@lanl.gov' - -# def parse_pflotran_input(pflotran_input_file): -# ''' Walk through PFLOTRAN input file and find inflow boundary, inflow and outflow pressure, and direction of flow - -# Parameters -# ---------- -# pflotran_input_file : string -# Name of PFLOTRAN input file - -# Returns -# ------- -# inflow_pressure : double -# Inflow Pressure boundary condition -# outflow_pressure : float -# Outflow pressure boundary condition -# inflow_file : string -# Name of inflow boundary .ex file -# direction : string -# Primary direction of flow x, y, or z - -# Notes -# ----- -# Currently only works for Dirichlet Boundary Conditions -# ''' - -# with open(pflotran_input_file) as fp: -# outflow_found = False -# inflow_found = False -# for line in fp.readlines(): -# if "BOUNDARY_CONDITION OUTFLOW" in line: -# outflow_found = True -# if outflow_found: -# if "REGION" in line: -# outflow = line.split()[-1] -# outflow_found = False -# if "BOUNDARY_CONDITION INFLOW" in line: -# inflow_found = True -# if inflow_found: -# if "REGION" in line: -# inflow = line.split()[-1] -# inflow_found = False - -# with open(pflotran_input_file) as fp: -# inflow_name_found = False -# outflow_name_found = False -# inflow_found = False -# outflow_found = False - -# for line in fp.readlines(): -# if "REGION " + inflow in line: -# inflow_name_found = True -# if inflow_name_found: -# if "FILE" in line: -# inflow_file = line.split()[-1] -# inflow_name_found = False -# if "FLOW_CONDITION " + inflow in line: -# inflow_found = True -# if inflow_found: -# if "PRESSURE " in line: -# if "dirichlet" not in line: -# tmp = line.split()[-1] -# tmp = tmp.split('d') -# inflow_pressure = float(tmp[0]) * 10**float(tmp[1]) -# inflow_found = False - -# if "REGION " + outflow in line: -# outflow_name_found = True -# if outflow_name_found: -# if "FILE" in line: -# outflow_file = line.split()[-1] -# outflow_name_found = False -# if "FLOW_CONDITION " + outflow in line: -# outflow_found = True -# if outflow_found: -# if "PRESSURE " in line: -# if "dirichlet" not in line: -# tmp = line.split()[-1] -# tmp = tmp.split('d') -# outflow_pressure = float(tmp[0]) * 10**float(tmp[1]) -# outflow_found = False - -# if inflow_file == 'pboundary_left_w.ex' or inflow_file == 'pboundary_right_e.ex': -# direction = 'x' -# if inflow_file == 'pboundary_front_n.ex' or inflow_file == 'pboundary_back_s.ex': -# direction = 'y' -# if inflow_file == 'pboundary_top.ex' or inflow_file == 'pboundary_bottom.ex': -# direction = 'z' - -# print("Inflow file: %s" % inflow_file) -# print("Inflow Pressure %e" % inflow_pressure) -# print("Outflow Pressure %e" % outflow_pressure) -# print("Primary Flow Direction : %s" % direction) - -# return inflow_pressure, outflow_pressure, inflow_file, direction - - -def check_inputs(boundary_file, direction, inflow_pressure, outflow_pressure): +__author__ = 'Jeffrey Hyman' +__email__ = 'jhyman@lanl.gov' + +def check_inputs(direction, inflow_pressure, outflow_pressure, boundary_file, darcy_vel_file): + """ + Checks that inflow pressure is greater than outflow pressure and that path to file paths are valid. + + Parameters + ---------------- + direction : string + Primary direction of flow (x, y, or z) + inflow_pressure : float + Inflow boundary pressure + outflow_pressure : float + Outflow Boundary pressure + boundary_file : string + Name of ex file for inflow boundary + darcy_vel_file : string + name of darcy veloctiy file (pflotran output file) + + Returns + ----------------- + Boolean + True if all tests pasted, False if not + """ + + if direction not in ['x', 'y', 'z']: + print(f"--> Error. Unknown direction provided {direction}. Acceptable values are 'x','y', and 'z'.\nExiting\n" + ) + return False ## Check Pressure if inflow_pressure < outflow_pressure: print( - "--> ERROR! Inflow Pressure less the outflow pressure. Cannot compute effective permeability" + "--> Error. Inflow pressure is less the outflow pressure. Cannot compute effective permeability.\n" ) + print(f"--> Inflow Pressure: {inflow_pressure}") + print(f"--> Outflow Pressure: {outflow_pressure}") + print("Exiting fucntion call.") return False if not os.path.exists(boundary_file): - print(f"--> ERROR! Boundary file not found. Please check path.") + print(f"--> Error. Boundary file: {boundary_file} not found. Please check path.\nExiting\n") return False + - ## Check Direction - fail = False - if direction == 'x': - if not boundary_file in [ - 'pboundary_left_w.ex', 'pboundary_right_e.ex' - ]: - print( - f"--> ERROR! Direction {direction} is not consistent with boundary file {boundary_file}. Cannot compute effective permeability." - ) - return False - - elif direction == 'y': - if not boundary_file in [ - 'pboundary_front_n.ex', 'pboundary_back_s.ex' - ]: - print( - f"--> ERROR! Direction {direction} is not consistent with boundary file {boundary_file}. Cannot compute effective permeability." - ) - return False - - elif direction == 'z': - if not boundary_file in ['pboundary_top.ex', 'pboundary_bottom.ex']: - print( - f"--> ERROR! Direction {direction} is not consistent with boundary file {boundary_file}. Cannot compute effective permeability." - ) - return False + if not os.path.exists(darcy_vel_file): + print(f"--> Error. Darcy velocity file: {darcy_vel_file} not found. Please check path.\nExiting\n") + return False + return True @@ -258,8 +173,8 @@

Source code for pydfnworks.dfnFlow.mass_balance

< Volumetric flow rate across the inflow boundary Notes - ----- - None + -------- + None ''' # Calculate the mass flow rate mass_rate = 0.0 #kg/s @@ -332,10 +247,10 @@

Source code for pydfnworks.dfnFlow.mass_balance

< Notes ----- - Information is written into (local_jobname)_effective_perm.txt + Information is written into <local_jobname>_effective_perm.txt ''' - Lm3 = domain['x'] * domain['y'] * domain['z'] #L/m^3 + # Lm3 = domain['x'] * domain['y'] * domain['z'] #L/m^3 # if flow is in x direction, cross section is domain['y']*domain['z'] if direction == 'x': surface = domain['y'] * domain['z'] @@ -373,9 +288,9 @@

Source code for pydfnworks.dfnFlow.mass_balance

< output_string += f'The effective permeability of the domain [m^2]: {q * mu / pgrad:0.5e}' print("\n--> Effective Permeability Properties: ") print(output_string) - fp = open(f'{local_jobname}_effective_perm.txt', "w") - fp.write(output_string) - fp.close() + with open(f'{local_jobname}_effective_perm.txt', "w") as fp: + fp.write(output_string) + keff = q * mu / pgrad return keff @@ -383,7 +298,7 @@

Source code for pydfnworks.dfnFlow.mass_balance

<
[docs] def effective_perm(self, inflow_pressure, outflow_pressure, boundary_file, - direction): + direction, darcy_vel_file = 'darcyvel.dat'): '''Computes the effective permeability of a DFN in the primary direction of flow using a steady-state PFLOTRAN solution. Parameters @@ -398,18 +313,20 @@

Source code for pydfnworks.dfnFlow.mass_balance

< Name of inflow boundary file, e.g., pboundary_left.ex direction: string Primary direction of flow, x, y, or z - + darcy_vel_file : string + Name of concatenated Darcy velocity file Returns ------- None Notes ----- - 1. Information is written to screen and to the file self.local_jobname_effective_perm.txt - 2. Currently, only PFLOTRAN solutions are supported - 3. Assumes density of water at 20c + 1. Information is written to screen and to the file self.local_jobname_effective_perm.txt + 2. Currently, only PFLOTRAN solutions are supported + 3. Assumes density of water at 20c ''' + print("--> Computing Effective Permeability of Block\n") if not self.flow_solver == "PFLOTRAN": print( @@ -417,19 +334,15 @@

Source code for pydfnworks.dfnFlow.mass_balance

< ) return 0 - darcy_vel_file = 'darcyvel.dat' - # pflotran_input_file = self.local_dfnFlow_file - - print(f"--> Inflow file name:\t\t{boundary_file}") + print(f"--> Inflow boundary file name:\t\t{boundary_file}") print(f"--> Darcy Velocity File:\t{darcy_vel_file}") print(f"--> Inflow Pressure:\t\t{inflow_pressure:0.5e} Pa") print(f"--> Outflow Pressure:\t\t{outflow_pressure:0.5e} Pa") print(f"--> Primary Flow Direction:\t{direction}") - if not check_inputs(boundary_file, direction, inflow_pressure, - outflow_pressure): + if not check_inputs(direction, inflow_pressure, outflow_pressure, boundary_file, darcy_vel_file): return 1 - + mass_rate, volume_rate = flow_rate(darcy_vel_file, boundary_file) keff = dump_effective_perm(self.local_jobname, mass_rate, volume_rate, self.domain, direction, inflow_pressure, diff --git a/docs/_modules/pydfnworks/dfnFlow/pflotran.html b/docs/_modules/pydfnworks/dfnFlow/pflotran.html index ea8fa84fb..de260e825 100644 --- a/docs/_modules/pydfnworks/dfnFlow/pflotran.html +++ b/docs/_modules/pydfnworks/dfnFlow/pflotran.html @@ -1,19 +1,21 @@ - + - pydfnworks.dfnFlow.pflotran — dfnWorks 2.7 documentation - - + pydfnworks.dfnFlow.pflotran — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
@@ -404,8 +406,11 @@

Source code for pydfnworks.dfnFlow.pflotran

         h5dset = h5file.create_dataset(dataset_name, data=iarray)
         print('--> Creating permeability array')
         print('--> Note: This script assumes isotropic permeability')
-        for i in range(self.num_nodes):
-            self.perm_cell[i] = self.perm[self.material_ids[i] - 1]
+        if self.cell_based_aperture: 
+            self.perm_cell = np.genfromtxt(self.perm_cell_file, skip_header = 1)[:,1]
+        else: 
+            for i in range(self.num_nodes):
+                self.perm_cell[i] = self.perm[self.material_ids[i] - 1]
         print('--> Writting Permeability')
         dataset_name = 'Permeability'
         h5dset = h5file.create_dataset(dataset_name, data=self.perm_cell)
diff --git a/docs/_modules/pydfnworks/dfnGen/generation/generator.html b/docs/_modules/pydfnworks/dfnGen/generation/generator.html
index 6416c7343..c805de5e2 100644
--- a/docs/_modules/pydfnworks/dfnGen/generation/generator.html
+++ b/docs/_modules/pydfnworks/dfnGen/generation/generator.html
@@ -1,19 +1,21 @@
 
-
+
 
   
   
-  pydfnworks.dfnGen.generation.generator — dfnWorks 2.7 documentation
-      
-      
+  pydfnworks.dfnGen.generation.generator — dfnWorks v2.8 documentation
+      
+      
+
+  
   
   
         
         
-        
-        
+        
+        
         
     
     
@@ -33,7 +35,7 @@
               
           
               
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
@@ -465,73 +467,115 @@

Source code for pydfnworks.dfnGen.generation.generator

family_id=i + 1) print("--> Assign hydraulic properties to fracture families : Complete ") - ### Assign variables for user defined fractures + ### Assign variables for user defined fractures and skip rejected fractures ##Logic here, loop through user defined fractures ## first check flag to insert - fracture_num = 1 + file_path = 'dfnGen_output/userFractureRejections.dat' + if os.path.isfile(file_path) and os.path.getsize(file_path) > 0: + try: + reject_fracs, frac_type = np.genfromtxt(file_path, delimiter = ',', skip_header = 1, unpack=True) + reject_fracs = np.array([reject_fracs]) #needed for case with one rejected fracture, genfromtxt reads in float otherwise + frac_type = np.array([frac_type]) + except: + print('--> No Rejected User Fractures, Ignore Following Warning.') + reject_fracs = np.array([]) + frac_type = np.array([]) + else: #if no fractures are rejected + print('--> No Rejected User Fractures, Ignore Following Warning.') + reject_fracs = np.array([]) + frac_type = np.array([]) + + rect_reject = reject_fracs[(frac_type == -2)] #integer corresponds to fracture type + ell_reject = reject_fracs[(frac_type == -1)] + poly_reject = reject_fracs[(frac_type == -3)] + + fracture_num = 1 #keep track of overall fracture number, and numbers for different types of fractures + frac_ell_num = 1 + frac_rect_num = 1 + frac_poly_num = 1 + if self.params['insertUserRectanglesFirst']['value'] == 0: print('--> Inserting User Ellipse Hydraulic Params First') for i in range(len(self.user_ell_params)): for j in range(self.user_ell_params[i]['nPolygons']): - print(f'--> Inserting User Ell Hydraulic Params {fracture_num}') - hy_prop_type = self.user_ell_params[i]['hy_prop_type'] - value = self.user_ell_params[i][hy_prop_type][j] - print(f'{hy_prop_type} = {value}') - self.set_fracture_hydraulic_values(hy_prop_type, [fracture_num], + if frac_ell_num not in ell_reject: + print(f'--> Inserting User Ell Hydraulic Params {fracture_num}') + hy_prop_type = self.user_ell_params[i]['hy_prop_type'] + value = self.user_ell_params[i][hy_prop_type][j] + print(f'{hy_prop_type} = {value}') + self.set_fracture_hydraulic_values(hy_prop_type, [fracture_num], [value]) - fracture_num += 1 + fracture_num += 1 + + frac_ell_num += 1 for i in range(len(self.user_rect_params)): for j in range(self.user_rect_params[i]['nPolygons']): - print(f'--> Inserting User Rect Hydraulic Params {fracture_num}') - hy_prop_type = self.user_rect_params[i]['hy_prop_type'] - value = self.user_rect_params[i][hy_prop_type][j] - print(f'{hy_prop_type} = {value}') - self.set_fracture_hydraulic_values(hy_prop_type, [fracture_num], + if frac_rect_num not in rect_reject: + print(f'--> Inserting User Rect Hydraulic Params {fracture_num}') + hy_prop_type = self.user_rect_params[i]['hy_prop_type'] + value = self.user_rect_params[i][hy_prop_type][j] + print(f'{hy_prop_type} = {value}') + self.set_fracture_hydraulic_values(hy_prop_type, [fracture_num], [value]) - fracture_num += 1 + fracture_num += 1 + + frac_rect_num += 1 for i in range(len(self.user_poly_params)): for j in range(self.user_poly_params[i]['nPolygons']): - print(f'--> Inserting User Poly Hydraulic Params {fracture_num}') - hy_prop_type = self.user_poly_params[i]['hy_prop_type'] - value = self.user_poly_params[i][hy_prop_type][j] - print(f'{hy_prop_type} = {value}') - self.set_fracture_hydraulic_values(hy_prop_type, [fracture_num], + if frac_poly_num not in poly_reject: + print(f'--> Inserting User Poly Hydraulic Params {fracture_num}') + hy_prop_type = self.user_poly_params[i]['hy_prop_type'] + value = self.user_poly_params[i][hy_prop_type][j] + print(f'{hy_prop_type} = {value}') + self.set_fracture_hydraulic_values(hy_prop_type, [fracture_num], [value]) - fracture_num += 1 + fracture_num += 1 + + frac_poly_num += 1 else: - print('--> Inserting User Rectangles Hydraulic Params First') + print('--> Inserting User Rectangle Hydraulic Params First') for i in range(len(self.user_rect_params)): for j in range(self.user_rect_params[i]['nPolygons']): - print(f'--> Inserting User Rect Hydraulic Params {fracture_num}') - hy_prop_type = self.user_rect_params[i]['hy_prop_type'] - value = self.user_rect_params[i][hy_prop_type][j] - print(f'{hy_prop_type} = {value}') - self.set_fracture_hydraulic_values(hy_prop_type, [fracture_num], + if frac_rect_num not in rect_reject: + print(f'--> Inserting User Rect Hydraulic Params {fracture_num}') + hy_prop_type = self.user_rect_params[i]['hy_prop_type'] + value = self.user_rect_params[i][hy_prop_type][j] + print(f'{hy_prop_type} = {value}') + self.set_fracture_hydraulic_values(hy_prop_type, [fracture_num], [value]) - fracture_num += 1 + fracture_num += 1 + + frac_rect_num += 1 for i in range(len(self.user_ell_params)): - for j in range(self.user_ell_params[i]['nPolygons']): - print(f'--> Inserting User Ell Hydraulic Params {fracture_num}') - hy_prop_type = self.user_ell_params[i]['hy_prop_type'] - value = self.user_ell_params[i][hy_prop_type][j] - print(f'{hy_prop_type} = {value}') - self.set_fracture_hydraulic_values(hy_prop_type, [fracture_num], + for j in range(self.user_ell_params[i]['nPolygons']): + if frac_ell_num not in ell_reject: + print(f'--> Inserting User Ell Hydraulic Params {fracture_num}') + hy_prop_type = self.user_ell_params[i]['hy_prop_type'] + value = self.user_ell_params[i][hy_prop_type][j] + print(f'{hy_prop_type} = {value}') + + self.set_fracture_hydraulic_values(hy_prop_type, [fracture_num], [value]) - fracture_num += 1 + fracture_num += 1 + + frac_ell_num += 1 for i in range(len(self.user_poly_params)): for j in range(self.user_poly_params[i]['nPolygons']): - print(f'--> Inserting User Poly Hydraulic Params {fracture_num}') - hy_prop_type = self.user_poly_params[i]['hy_prop_type'] - value = self.user_poly_params[i][hy_prop_type][j] - print(f'{hy_prop_type} = {value}') - self.set_fracture_hydraulic_values(hy_prop_type, [fracture_num], + if frac_poly_num not in poly_reject: + print(f'--> Inserting User Poly Hydraulic Params {fracture_num}') + hy_prop_type = self.user_poly_params[i]['hy_prop_type'] + value = self.user_poly_params[i][hy_prop_type][j] + print(f'{hy_prop_type} = {value}') + self.set_fracture_hydraulic_values(hy_prop_type, [fracture_num], [value]) - fracture_num += 1 + fracture_num += 1 + + frac_poly_num += 1 # self.dump_hydraulic_values() print("--> Assign hydraulic properties: Complete ") diff --git a/docs/_modules/pydfnworks/dfnGen/generation/input_checking/check_input.html b/docs/_modules/pydfnworks/dfnGen/generation/input_checking/check_input.html index a1a4d7125..14fcd21bb 100644 --- a/docs/_modules/pydfnworks/dfnGen/generation/input_checking/check_input.html +++ b/docs/_modules/pydfnworks/dfnGen/generation/input_checking/check_input.html @@ -1,19 +1,21 @@ - + - pydfnworks.dfnGen.generation.input_checking.check_input — dfnWorks 2.7 documentation - - + pydfnworks.dfnGen.generation.input_checking.check_input — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/_modules/pydfnworks/dfnGen/generation/input_checking/fracture_family.html b/docs/_modules/pydfnworks/dfnGen/generation/input_checking/fracture_family.html index 3089769f5..e549be22d 100644 --- a/docs/_modules/pydfnworks/dfnGen/generation/input_checking/fracture_family.html +++ b/docs/_modules/pydfnworks/dfnGen/generation/input_checking/fracture_family.html @@ -1,19 +1,21 @@ - + - pydfnworks.dfnGen.generation.input_checking.fracture_family — dfnWorks 2.7 documentation - - + pydfnworks.dfnGen.generation.input_checking.fracture_family — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/_modules/pydfnworks/dfnGen/generation/input_checking/user_defined_fracture_functions.html b/docs/_modules/pydfnworks/dfnGen/generation/input_checking/user_defined_fracture_functions.html index 817ec5a70..8d431d8b2 100644 --- a/docs/_modules/pydfnworks/dfnGen/generation/input_checking/user_defined_fracture_functions.html +++ b/docs/_modules/pydfnworks/dfnGen/generation/input_checking/user_defined_fracture_functions.html @@ -1,19 +1,21 @@ - + - pydfnworks.dfnGen.generation.input_checking.user_defined_fracture_functions — dfnWorks 2.7 documentation - - + pydfnworks.dfnGen.generation.input_checking.user_defined_fracture_functions — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/_modules/pydfnworks/dfnGen/generation/output_report/gen_output.html b/docs/_modules/pydfnworks/dfnGen/generation/output_report/gen_output.html index 1a76212ad..970168f55 100644 --- a/docs/_modules/pydfnworks/dfnGen/generation/output_report/gen_output.html +++ b/docs/_modules/pydfnworks/dfnGen/generation/output_report/gen_output.html @@ -1,19 +1,21 @@ - + - pydfnworks.dfnGen.generation.output_report.gen_output — dfnWorks 2.7 documentation - - + pydfnworks.dfnGen.generation.output_report.gen_output — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/_modules/pydfnworks/dfnGen/generation/stress.html b/docs/_modules/pydfnworks/dfnGen/generation/stress.html index 15f5ce901..e6d3630e0 100644 --- a/docs/_modules/pydfnworks/dfnGen/generation/stress.html +++ b/docs/_modules/pydfnworks/dfnGen/generation/stress.html @@ -1,19 +1,21 @@ - + - pydfnworks.dfnGen.generation.stress — dfnWorks 2.7 documentation - - + pydfnworks.dfnGen.generation.stress — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/_modules/pydfnworks/dfnGen/meshing/add_attribute_to_mesh.html b/docs/_modules/pydfnworks/dfnGen/meshing/add_attribute_to_mesh.html index a7b1968aa..ff22edd55 100644 --- a/docs/_modules/pydfnworks/dfnGen/meshing/add_attribute_to_mesh.html +++ b/docs/_modules/pydfnworks/dfnGen/meshing/add_attribute_to_mesh.html @@ -1,19 +1,21 @@ - + - pydfnworks.dfnGen.meshing.add_attribute_to_mesh — dfnWorks 2.7 documentation - - + pydfnworks.dfnGen.meshing.add_attribute_to_mesh — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/_modules/pydfnworks/dfnGen/meshing/dfm/mesh_dfm.html b/docs/_modules/pydfnworks/dfnGen/meshing/dfm/mesh_dfm.html new file mode 100644 index 000000000..8a1b2be42 --- /dev/null +++ b/docs/_modules/pydfnworks/dfnGen/meshing/dfm/mesh_dfm.html @@ -0,0 +1,1214 @@ + + + + + + pydfnworks.dfnGen.meshing.dfm.mesh_dfm — dfnWorks v2.8 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for pydfnworks.dfnGen.meshing.dfm.mesh_dfm

+"""
+.. module:: mesh_dfm.py
+   :synopsis: meshing driver for conforming DFM  
+.. moduleauthor:: Jeffrey Hyman <jhyman@lanl.gov>
+
+"""
+
+import os
+import sys
+import shutil
+import glob 
+
+# pydfnworks Modules
+from pydfnworks.dfnGen.meshing.mesh_dfn import mesh_dfn_helper as mh
+
+def setup_mesh_dfm_directory(jobname, dirname):
+    """ Setup working directory for meshing the DFM. 
+
+    Parameters
+    ----------------
+        jobname : string
+            path to DFN working directory 
+        dirname : string 
+            name of working directory
+
+    Returns
+    --------------
+        None
+
+    Notes
+    -------------
+        None 
+    """
+    path = jobname + os.sep + dirname
+    try: 
+        os.mkdir(path)
+        os.chdir(path)
+    except:
+        shutil.rmtree(path)
+        os.mkdir(path)
+        os.chdir(path)
+
+
+    print(f"--> Working directory is now {os.getcwd()}")
+    # Make symbolic links to required files
+    try:
+        os.symlink(jobname + os.sep + "full_mesh.inp", "full_mesh.inp")
+    except:
+        error = f"Error. Unable to make symbolic link to full_mesh.inp file for DFM meshing from {jobname}.\nExitting program."
+        sys.stderr.write(error)
+        sys.exit(1)
+
+    print("--> Setting up DFM meshing directory complete")
+
+
+
+def translate_mesh(x1, x2):
+    """
+    Moves reduced_mesh.inp from center at x1 to x2 
+
+    Parameters
+    ---------------
+        x1 : list
+            floats x-0, y-1, z-2 - current center
+
+        x2 : list
+            floats x-0, y-1, z-2 - requisted center 
+    Returns
+    --------------
+        None 
+
+    """
+
+    lagrit_script = f"""
+read / avs / full_mesh.inp / MODFN
+trans / 1 0 0 / {x1[0]} {x1[1]} {x1[2]} / {x2[0]} {x2[1]} {x2[2]}
+cmo / printatt / MODFN / -xyz- / minmax
+dump / full_mesh.inp / MODFN
+finish
+"""
+    with open('translate_mesh.lgi', 'w') as fp:
+        fp.write(lagrit_script)
+        fp.flush()
+    mh.run_lagrit_script("translate_mesh.lgi")
+
+
+def create_domain(domain, h):
+    """ Gather domain information. 
+
+    Parameters
+    ----------
+        domain : dict
+            Domain size dictionary from DFN object 
+        h : float 
+            Meshing length scale from DFN object 
+
+    Returns
+    -------
+        num_points : int 
+            Number of points on side of the domain 
+        box_domain : dict
+            dictionary of domain min/max for x,y,z
+
+    Notes
+    ------
+        Exits program is too many points are in domain. 
+        Assuming that 
+
+    """
+    box_domain = {"x0": None, "x0": None,
+                  "y0": None, "y1": None, 
+                  "z0": None, "z1": None 
+                  }
+
+    # Extent of domain
+    box_domain['x0'] = -0.5*domain['x']
+    box_domain['x1'] = 0.5*domain['x']
+
+    box_domain['y0'] = -0.5*domain['y'] 
+    box_domain['y1'] = 0.5*domain['y'] 
+
+    box_domain['z0'] = -0.5*domain['z']
+    box_domain['z1'] = 0.5*domain['z']
+
+    # Mesh size in matrix
+    l = h/2
+    # # Number of points in each direction in matrix
+    # num_points = domain['x'] / l + 1
+    # if num_points**3 > 1e8:
+    #     error = f"Error: Too many elements for DFM meshing.\nValue {num_points**3}\nMaximum is 1e8\nExiting Program"
+    #     sys.stderr.write(error)
+    #     sys.exit(1)
+
+    num_points_x = domain['x'] / l + 1
+    num_points_y = domain['y'] / l + 1
+    num_points_z = domain['z'] / l + 1
+    if num_points_x*num_points_y*num_points_z > 1e8:
+        error = f"Error: Too many elements for DFM meshing.\nValue {num_points_x*num_points_y*num_points_z }\nMaximum is 1e8\nExiting Program"
+        sys.stderr.write(error)
+        sys.exit(1)
+    return box_domain, num_points_x, num_points_y, num_points_z 
+
+def dfm_driver(num_points_x, num_points_y, num_points_z , num_fracs, h, box_domain, psets):
+    """ This function creates the main lagrit driver script, which calls the other lagrit scripts.
+
+    Parameters
+    ----------
+        num_points : int 
+            Number of points on side of the domain 
+        num_fracs : int 
+            Number of Fractures in the DFN
+        h : float
+            meshing length scale 
+
+    Returns
+    -------
+        None
+
+    Notes
+    -----
+        None 
+    """
+    floop = ""
+    for ifrac in range(1, num_fracs + 1):
+        if ifrac < num_fracs:
+            floop += f"facets_f{ifrac}.table &\n"
+        else:
+            floop += f"facets_f{ifrac}.table &\n"
+            floop += "left.table &\n"
+            floop += "right.table &\n"
+            floop += "front.table &\n"
+            floop += "back.table &\n"
+            floop += "top.table &\n"
+            floop += "bottom.table"
+            
+    lagrit_script  = f"""#
+#   dfm_mesh_fracture_driver.lgi
+#   dfm_box_dimensions.mlgi
+#   dfm_build_background_mesh.mlgi
+#   dfm_extract_fracture_facets.mlgi
+#   dfm_extract_facets.mlgi
+#
+# extract_fracture_facets.mlgi must be customized for the number of fractures in the DFN
+#
+# This is the dfnWorks DFN mesh
+#
+define / INPUT / full_mesh.inp
+read / avs / INPUT / mo_dfn
+cmo / DELATT / mo_dfn / dfield
+cmo / DELATT / mo_dfn / b_a
+cmo / DELATT / mo_dfn / numbnd
+cmo / DELATT / mo_dfn / if_numb
+#
+# Diagnostics on fracture mesh extents and resolution
+#
+cmo / printatt / mo_dfn / -xyz- / minmax
+quality
+quality/edge_min
+quality/edge_max
+#
+# Define a resolution for the background mesh. This assumes the DFN
+# triangulation is uniform resolution triangles. No attempt is made
+# to adapt the volume mesh resolution to the DFN triangle resolution.
+#
+define / NPX / {num_points_x}
+# define / NPXM1 / {num_points_x - 1}
+define / NPY / {num_points_y}
+# define / NPYM1 / {num_points_y - 1}
+define / NPZ / {num_points_z}
+# define / NPZM1 / {num_points_z - 1}
+define / VERTEX_CLOSE / {h / 4}
+#
+define / MO_BACKGROUND / mo_background
+infile dfm_box_dimensions.mlgi
+infile dfm_build_background_mesh.mlgi
+#
+# Remove all vertices of the tet mesh that fall withing a circumsphere of a fracture triangle.
+#
+addmesh / excavate / mo_tmp / MO_BACKGROUND / mo_dfn
+cmo / delete / MO_BACKGROUND
+#
+# Merge the vertices of the excavated tet mesh with the DFN vertices
+#
+cmo / create / mo_dfm / / / tet
+copypts / mo_dfm / mo_tmp
+cmo / delete / mo_tmp
+compute / distance_field / mo_dfm / mo_dfn / df_vertex
+cmo / select / mo_dfm
+pset / pdel / attribute / df_vertex / 1 0 0 / le VERTEX_CLOSE
+rmpoint / pset get pdel / inclusive
+rmpoint / compress
+cmo / DELATT / mo_dfm / df_vertex
+copypts / mo_dfm / mo_dfn
+#
+cmo / setatt / mo_dfm / imt / 1 0 0 / 1
+cmo / setatt / mo_dfm / itp / 1 0 0 / 0
+cmo / select / mo_dfm
+connect
+cmo / setatt / mo_dfm / itetclr / 1 0 0 / 1
+resetpts / itp
+quality
+#
+#compute / signed_distance_field / mo_dfm / mo_dfn / df_sign_dfm_dfn
+#
+# crush_thin_tets / mo_dfm / 0.25 / 1 0 0 
+dump / avs    / dfm_tet_mesh.inp / mo_dfm
+dump / lagrit / dfm_tet_mesh.lg  / mo_dfm
+dump / exo    / dfm_tet_mesh.exo / mo_dfm
+
+cmo / delete / mo_dfm
+cmo / delete / mo_dfn
+#
+cmo / status / brief
+#
+infile dfm_extract_fracture_facets.mlgi
+infile dfm_diagnostics.mlgi
+#
+# Delete this !!!! 
+# Hardcoded facesets on boundaries for Alex EES17
+cmo / select / mo_dfm
+extract / surfmesh / 1 0 0 / mo_surf / mo_dfm / external
+cmo / addatt / mo_surf / id_side / vint / scalar / nelements
+cmo / select / mo_surf
+settets / normal
+cmo / copyatt / mo_surf mo_surf / id_side itetclr
+cmo / printatt / mo_surf / id_side / minmax
+cmo / DELATT / mo_surf / itetclr0
+cmo / DELATT / mo_surf / idnode0
+cmo / DELATT / mo_surf / idelem0
+cmo / DELATT / mo_surf / facecol
+cmo / DELATT / mo_surf / itetclr1
+cmo / DELATT / mo_surf / idface0
+#
+cmo / copy / mo_tmp / mo_surf
+cmo / select / mo_tmp
+eltset / e_bottom / id_side / eq / 1
+eltset / e_delete / not / e_bottom
+rmpoint / element / eltset get e_delete
+rmpoint / compress
+cmo / DELATT / mo_tmp / id_side
+dump / avs2 / bottom.table / mo_tmp / 0 0 0 2
+cmo / delete / mo_tmp
+#
+cmo / copy / mo_tmp / mo_surf
+cmo / select / mo_tmp
+eltset / e_top / id_side / eq / 2
+eltset / e_delete / not / e_top
+rmpoint / element / eltset get e_delete
+rmpoint / compress
+cmo / DELATT / mo_tmp / id_side
+dump / avs2 / top.table / mo_tmp / 0 0 0 2
+cmo / delete / mo_tmp
+#
+cmo / copy / mo_tmp / mo_surf
+cmo / select / mo_tmp
+eltset / e_right / id_side / eq / 3
+eltset / e_delete / not / e_right
+rmpoint / element / eltset get e_delete
+rmpoint / compress
+cmo / DELATT / mo_tmp / id_side
+dump / avs2 / right.table / mo_tmp / 0 0 0 2
+cmo / delete / mo_tmp
+#
+cmo / copy / mo_tmp / mo_surf
+cmo / select / mo_tmp
+eltset / e_back / id_side / eq / 4
+eltset / e_delete / not / e_back
+rmpoint / element / eltset get e_delete
+rmpoint / compress
+cmo / DELATT / mo_tmp / id_side
+dump / avs2 / back.table / mo_tmp / 0 0 0 2
+cmo / delete / mo_tmp
+#
+cmo / copy / mo_tmp / mo_surf
+cmo / select / mo_tmp
+eltset / e_left / id_side / eq / 5
+eltset / e_delete / not / e_left
+rmpoint / element / eltset get e_delete
+rmpoint / compress
+cmo / DELATT / mo_tmp / id_side
+dump / avs2 / left.table / mo_tmp / 0 0 0 2
+cmo / delete / mo_tmp
+#
+cmo / copy / mo_tmp / mo_surf
+cmo / select / mo_tmp
+eltset / e_front / id_side / eq / 6
+eltset / e_delete / not / e_front
+rmpoint / element / eltset get e_delete
+rmpoint / compress
+cmo / DELATT / mo_tmp / id_side
+dump / avs2 / front.table / mo_tmp / 0 0 0 2
+cmo / delete / mo_tmp
+#
+"""
+    
+    if psets:
+        eps = h/4
+        lagrit_script += f"""
+cmo / select / mo_dfm
+cmo / printatt / mo_dfm / -xyz- / minmax
+
+pset/ pleft / geom / xyz / 1, 0, 0 /  &
+     {box_domain['x0'] - eps} {box_domain['y0']} {box_domain['z0']} / {box_domain['x0'] + eps} {box_domain['y1']} {box_domain['z1']}  / 0,0,0
+pset/ pright / geom / xyz / 1, 0, 0 / &
+    {box_domain['x1'] - eps} {box_domain['y0']} {box_domain['z0']} / {box_domain['x1'] + eps} {box_domain['y1']} {box_domain['z1']}  / 0,0,0
+
+pset / pfront / geom / xyz / 1, 0, 0 / & 
+    {box_domain['x0']} {box_domain['y0'] - eps}  {box_domain['z0']} / {box_domain['x1']}  {box_domain['y0'] + eps}  {box_domain['z1']}  / 0,0,0 
+pset / pback / geom / xyz / 1, 0, 0 / & 
+    {box_domain['x0']} {box_domain['y1'] - eps}  {box_domain['z0']}  / {box_domain['x1']}  {box_domain['y1'] + eps}  {box_domain['z1']}  / 0,0,0 
+
+pset / pbottom / geom / xyz / 1, 0, 0 / &
+    {box_domain['x0']} {box_domain['y0']} {box_domain['z0'] - eps} / {box_domain['x1']}  {box_domain['y1']} {box_domain['z0'] + eps}/ 0,0,0 
+pset / ptop / geom / xyz / 1, 0, 0 /  & 
+    {box_domain['x0']} {box_domain['y0']} {box_domain['z1'] - eps} / {box_domain['x1']}  {box_domain['y1']} {box_domain['z1'] + eps} / 0,0,0 
+
+# corners of the mesh 1
+pset / p_tmp / inter / pleft pbottom
+pset / p_corner_lfb / inter / p_tmp pfront 
+pset / p_tmp / delete 
+
+pset / pbottom / not / pbottom p_corner_lfb
+pset / pleft / not / pleft p_corner_lfb
+pset / pfront / not / pfront p_corner_lfb
+
+
+cmo / addatt / mo_dfm / p_corner_lfb / vint / scalar / nnodes
+cmo/setatt / mo_dfm / p_corner_lfb / 1,0,0 / 0
+cmo/setatt / mo_dfm / p_corner_lfb /pset,get,p_corner_lfb / 1
+
+# corners of the mesh 2
+pset / p_tmp / inter / pright pbottom
+pset / p_corner_rfb / inter / p_tmp pfront 
+pset / p_tmp / delete 
+
+pset / pbottom / not / pbottom p_corner_rfb
+pset / pright / not / pright p_rfp_corner
+pset / pfront / not / pfront p_corner_rfb
+
+cmo / addatt / mo_dfm / p_corner_rfb / vint / scalar / nnodes
+cmo/setatt / mo_dfm / p_corner_rfb / 1,0,0 / 0
+cmo/setatt / mo_dfm / p_corner_rfb /pset,get,p_corner_rfb / 1
+
+# corners of the mesh 3
+pset / p_tmp / inter / pleft ptop
+pset / p_corner_lft / inter / p_tmp pfront 
+
+pset / pbottom / not / pbottom p_corner_lft
+pset / pleft / not / pleft p_corner_lft
+pset / pfront / not / pfront p_corner_lft
+pset / p_tmp / delete 
+
+cmo / addatt / mo_dfm / p_corner_lft / vint / scalar / nnodes
+cmo/setatt / mo_dfm / p_corner_lft / 1,0,0 / 0
+cmo/setatt / mo_dfm / p_corner_lft /pset,get,p_corner_lft / 1
+
+# corners of the mesh 4
+pset / p_tmp / inter / pright ptop 
+pset / p_corner_rft / inter / p_tmp pfront 
+pset / p_tmp / delete 
+
+pset / ptop / not / ptop p_corner_rft
+pset / pright / not / pright p_corner_rft
+pset / pfront / not / pfront p_corner_rft
+
+
+
+cmo / addatt / mo_dfm / p_corner_rft / vint / scalar / nnodes
+cmo/setatt / mo_dfm / p_corner_rft / 1,0,0 / 0
+cmo/setatt / mo_dfm / p_corner_rft /pset,get,p_corner_rft / 1
+
+
+
+### back face 
+
+# corners of the mesh 1
+pset / p_tmp / inter / pleft pbottom
+pset / p_corner_lbb / inter / p_tmp pback 
+pset / p_tmp / delete 
+
+
+# corners of the mesh 2
+pset / p_tmp / inter / pright pbottom
+pset / p_corner_rbb / inter / p_tmp pback 
+pset / p_tmp / delete 
+
+
+# corners of the mesh 3
+pset / p_tmp / inter / pleft ptop
+pset / p_corner_lbt / inter / p_tmp pback 
+pset / p_tmp / delete 
+
+
+# corners of the mesh 4
+pset / p_tmp / inter / pright ptop 
+pset / p_corner_rbt / inter / p_tmp pback 
+pset / p_tmp / delete 
+
+########
+
+cmo / addatt / mo_dfm / p_corner_rbt / vint / scalar / nnodes
+cmo/setatt / mo_dfm / p_corner_rbt / 1,0,0 / 0
+cmo/setatt / mo_dfm / p_corner_rbt /pset,get,p_corner_rbt / 1
+
+cmo / addatt / mo_dfm / p_corner_lbt / vint / scalar / nnodes
+cmo/setatt / mo_dfm / p_corner_lbt / 1,0,0 / 0
+cmo/setatt / mo_dfm / p_corner_lbt /pset,get,p_corner_lbt / 1
+
+
+cmo / addatt / mo_dfm / p_corner_lbb / vint / scalar / nnodes
+cmo/setatt / mo_dfm / p_corner_lbb / 1,0,0 / 0
+cmo/setatt / mo_dfm / p_corner_lbb /pset,get,p_corner_lbb / 1
+
+cmo / addatt / mo_dfm / p_corner_rbb / vint / scalar / nnodes
+cmo/setatt / mo_dfm / p_corner_rbb / 1,0,0 / 0
+cmo/setatt / mo_dfm / p_corner_rbb /pset,get,p_corner_rbb / 1
+
+## clean up PSETS TO MESH 
+pset / pbottom / not / pbottom p_corner_lbb
+pset / pleft / not / pleft p_corner_lbb
+pset / pback / not / pback p_corner_lbb
+
+pset / pbottom / not / pbottom p_corner_rbb
+pset / pright / not / pright p_corner_rbb
+pset / pback / not / pback p_corner_rbb
+
+pset / ptop / not / ptop p_corner_lbt
+pset / pleft / not / pleft p_corner_lbt
+pset / pback / not / pback p_corner_lbt
+
+pset / ptop / not / ptop p_corner_rbt
+pset / pright / not / pright p_corner_rbt
+pset / pback / not / pback p_corner_rbt
+
+
+pset / pbottom / not / pbottom p_corner_lfb
+pset / pleft / not / pleft p_corner_lfb
+pset / pfront / not / pfront p_corner_lfb 
+
+pset / pbottom / not / pbottom p_corner_rfb
+pset / pright / not / pright p_corner_rfb
+pset / pfront / not / pfront p_corner_rfb
+
+pset / ptop / not / ptop p_corner_lft
+pset / pleft / not / pleft p_corner_lft
+pset / pfront / not / pfront p_corner_lft
+
+pset / ptop / not / ptop p_corner_rft
+pset / pright / not / pright p_corner_rft
+pset / pfront / not / pfront p_corner_rft
+
+
+
+### edges ##### 
+
+pset / p_edge_lb / inter / pleft pbottom
+pset / pbottom / not / pbottom p_edge_lb
+pset / pleft / not / pleft p_edge_lb
+
+pset / p_edge_lt / inter / pleft ptop
+pset / ptop / not / ptop p_edge_lt
+pset / pleft / not / pleft p_edge_lt
+
+pset / p_edge_rb / inter / pright pbottom
+pset / pbottom / not / pbottom p_edge_rb
+pset / pright / not / pright p_edge_rb
+
+pset / p_edge_rt / inter / pright ptop 
+pset / ptop / not / ptop p_edge_rt
+pset / pright / not / pright p_edge_rt
+
+####### 
+pset / p_edge_lfr / inter / pleft pfront
+pset / pleft / not / pleft p_edge_lfr
+pset / pfront / not / pfront p_edge_lfr
+
+pset / p_edge_lba / inter / pleft pback 
+pset / pleft / not / pleft p_edge_lba
+pset / pback / not / pback p_edge_lba
+
+pset / p_edge_rfr / inter / pright pfront
+pset / pright / not / pright p_edge_rfr
+pset / pfront / not / pfront p_edge_rfr
+
+pset / p_edge_rba / inter / pright pback 
+pset / pright / not / pright p_edge_rba
+pset / pback / not / pback p_edge_rba
+
+####### 
+
+
+pset / p_edge_frb / inter / pfront pbottom
+pset / pfront / not / pfront p_edge_frb
+pset / pbottom / not / pbottom p_edge_frb
+
+pset / p_edge_bab / inter / pback pbottom
+pset / pback / not / pback p_edge_bab
+pset / pbottom / not / pbottom p_edge_bab
+
+pset / p_edge_frtop / inter / pfront ptop
+pset / pfront / not / pfront p_edge_frtop
+pset / ptop / not / ptop p_edge_frtop
+
+pset / p_edge_btop / inter /  pback ptop
+pset / pback / not / pback p_edge_btop
+pset / ptop / not / ptop p_edge_btop
+
+####### 
+
+cmo / addatt / mo_dfm / right / vint / scalar / nnodes
+cmo/setatt / mo_dfm / right / 1,0,0 / 0
+cmo/setatt / mo_dfm / right /pset,get,pright / 1
+
+cmo / addatt / mo_dfm / back / vint / scalar / nnodes
+cmo/setatt / mo_dfm / back / 1,0,0 / 0
+cmo/setatt / mo_dfm / back /pset,get,pback / 1
+
+
+cmo / addatt / mo_dfm / left / vint / scalar / nnodes
+cmo/setatt / mo_dfm / left / 1,0,0 / 0
+cmo/setatt / mo_dfm / left /pset,get,pleft / 1
+
+cmo / addatt / mo_dfm / top / vint / scalar / nnodes
+cmo/setatt / mo_dfm / top / 1,0,0 / 0
+cmo/setatt / mo_dfm / top /pset,get,ptop / 1
+
+cmo / addatt / mo_dfm / bottom / vint / scalar / nnodes
+cmo/setatt / mo_dfm / bottom / 1,0,0 / 0
+cmo/setatt / mo_dfm / bottom /pset,get,pbottom / 1
+
+cmo / addatt / mo_dfm / front / vint / scalar / nnodes
+cmo/setatt / mo_dfm / front / 1,0,0 / 0
+cmo/setatt / mo_dfm / front /pset,get,pfront / 1
+
+dump / dfm_tet_w_psets.inp / mo_dfm
+dump / exo / dfm_tet_mesh_w_fsets.exo / mo_dfm / psets / / &
+     facesets &
+"""
+        lagrit_script += floop 
+        lagrit_script += """
+finish
+"""
+    else: ## no psets
+        lagrit_script += """
+dump / exo / dfm_tet_mesh_w_fsets.exo / mo_dfm / / / &
+     facesets &
+"""
+        lagrit_script += floop 
+        lagrit_script += """
+finish
+"""
+
+    with open('dfm_mesh_fracture_driver.lgi', 'w') as fp:
+        fp.write(lagrit_script)
+        fp.flush()
+
+    print("Creating dfm_mesh_fracture_driver.lgi file: Complete\n")
+
+def dfm_box(box_domain):    
+    """ This function creates the dfm_box_dimensions.mlgi lagrit script.
+
+    Parameters
+    ----------
+        box_domain : dict
+            dictionary of domain min/max for x,y,z
+  
+    Returns
+    -------
+        None 
+
+    Notes
+    -----
+        None 
+
+    """
+
+    lagrit_script = f"""#
+# Define a bounding box that surrounds, and is a big bigger, than the DFN
+#
+define / X0 / {box_domain['x0']}
+define / X1 / {box_domain['x1']}
+define / Y0 / {box_domain['y0']}
+define / Y1 / {box_domain['y1']}
+define / Z0 / {box_domain['z0']}
+define / Z1 / {box_domain['z1']}
+
+finish
+"""
+    with open('dfm_box_dimensions.mlgi', 'w') as fp:
+        fp.write(lagrit_script)
+        fp.flush()
+
+    print("Creating dfm_box_dimensions.mlgi file: Complete\n")
+
+def dfm_build():
+    """ Create the dfm_build_background_mesh.mlgi lagrit script.
+
+    Parameters
+    ----------
+        None 
+
+    Returns
+    -------
+        None 
+
+    Notes
+    -----
+        Needs to be modified to have different NPX, NPY, NPZ 
+    """
+
+    lagrit_script = """#
+# Build a uniform background point distribution.
+#
+cmo / create / MO_BACKGROUND / / / tet
+createpts / xyz / NPX NPY NPZ / X0 Y0 Z0 / X1 Y1 Z1 / 1 1 1
+cmo / setatt / MO_BACKGROUND / imt / 1 0 0 / 1
+connect / noadd
+cmo / setatt / MO_BACKGROUND / itetclr / 1 0 0 / 1
+#
+finish
+"""
+    with open('dfm_build_background_mesh.mlgi', 'w') as fp: 
+        fp.write(lagrit_script)
+        fp.flush()
+    print("Creating dfm_box_dimensions.mlgi file: Complete\n")
+
+def dfm_fracture_facets(num_frac):
+    """ This function creates the dfm_extract_fracture_facets.mlgi lagrit script.
+
+    Parameters
+    ----------
+        num_frac : int 
+            Number of fractures in the DFN
+    
+    Returns
+    -------
+        None
+
+    Notes
+    -----
+        None 
+    """
+    floop1 = ""
+    floop2 = ""
+    for ifrac in range(1,num_frac+1):
+        floop1 += f"""
+define / FRAC_ID / {ifrac}
+define / FRAC_FILE_OUT / facets_f{ifrac}.inp
+define / FRAC_TABLE_OUT / facets_f{ifrac}.table
+#
+infile dfm_extract_facets.mlgi
+        """
+        if ifrac == 1:
+            floop2 += f"""
+read / avs / facets_f{ifrac}.inp / mo_merge
+cmo / setatt / mo_merge / itetclr / 1 0 0 / {ifrac}
+        """
+        else:
+            floop2 += f"""
+read / avs / facets_f{ifrac}.inp / mo
+cmo / setatt / mo / itetclr / 1 0 0 / {ifrac}
+addmesh / merge / mo_merge / mo_merge / mo
+cmo / delete / mo
+        """
+    lagrit_script = """#
+define / INPUT / full_mesh.inp
+define / MO_ONE_FRAC / mo_tmp_one_fracture
+#
+read / avs / dfm_tet_mesh.inp / mo_dfm
+#
+cmo / create / mo_merge
+cmo / status / brief
+read / avs / INPUT / mo_dfn
+cmo / status / brief
+""" + floop1 + floop2 + """
+dump / avs / facets_merged.inp / mo_merge
+cmo / addatt / mo_merge / id_frac / vint / scalar / nelements
+cmo / copyatt / mo_merge / mo_merge / id_frac / itetclr
+dump / avs / facets_merged.table / mo_merge / 0 0 0 2
+cmo / delete / mo_merge
+
+finish
+"""
+    with open('dfm_extract_fracture_facets.mlgi', 'w') as fp:
+        fp.write(lagrit_script)
+        fp.flush()
+    print("Creating dfm_extract_fracture_facets.mlgi file: Complete\n")
+
+def dfm_facets():
+    """ This function creates the dfm_extract_facets.mlgi lagrit script.
+
+    Parameters
+    ----------
+        None 
+
+    Returns
+    -------
+        None 
+
+    Notes
+    -----
+        None
+
+    """
+
+    lagrit_script = f"""#
+cmo / copy / MO_ONE_FRAC / mo_dfn
+cmo / select / MO_ONE_FRAC
+rmmat / FRAC_ID / element / exclusive
+rmpoint / compress
+resetpts / itp
+cmo / status / brief
+#
+compute / signed_distance_field / mo_dfm / MO_ONE_FRAC / dfield_sign
+
+cmo / delete / MO_ONE_FRAC
+#
+cmo / copy / mo_df_work / mo_dfm
+
+cmo / DELATT / mo_dfm / dfield_sign
+
+cmo / select / mo_df_work
+pset / p1 / attribute / dfield_sign / 1 0 0 / gt 0.0
+pset / p2 / attribute / dfield_sign / 1 0 0 / lt 0.0
+eltset / e1 / inclusive / pset get p1
+eltset / e2 / inclusive / pset get p2
+cmo / setatt / mo_df_work / itetclr / eltset get e1 / 1
+cmo / setatt / mo_df_work / itetclr / eltset get e2 / 2
+resetpts / itp
+extract / surfmesh / 1 0 0 / MO_ONE_FRAC_EXTRACT / mo_df_work
+#
+cmo / select / MO_ONE_FRAC_EXTRACT
+eltset / edel / idelem0 / eq / 0
+rmpoint / element / eltset get edel
+rmpoint / compress
+pset / pdel / attribute / dfield_sign / 1 0 0 / gt / 1.e-9
+rmpoint / pset get pdel / inclusive
+rmpoint / compress
+#
+# idelem0, idelem1 are element numbers
+# idface0, idface1 are the face numbers
+#
+cmo / DELATT / MO_ONE_FRAC_EXTRACT / itetclr0
+cmo / DELATT / MO_ONE_FRAC_EXTRACT / itetclr1
+cmo / DELATT / MO_ONE_FRAC_EXTRACT / facecol
+#
+# Don't keep both sides of the fracture face information.
+#
+cmo / DELATT / MO_ONE_FRAC_EXTRACT / idelem0
+cmo / DELATT / MO_ONE_FRAC_EXTRACT / idface0
+#
+dump / avs2 / FRAC_FILE_OUT  / MO_ONE_FRAC_EXTRACT
+dump / avs2 / FRAC_TABLE_OUT / MO_ONE_FRAC_EXTRACT  / 0 0 0 2
+#
+cmo / delete / MO_ONE_FRAC_EXTRACT
+#
+cmo / status / brief
+#
+finish
+"""
+    with open('dfm_extract_facets.mlgi', 'w') as fp:
+        fp.write(lagrit_script)
+        fp.flush()
+
+    print("Creating dfm_extract_facets.mlgi file: Complete\n")
+
+
+def dfm_diagnostics(h):
+    """
+    
+    """
+    eps_offset = 0.1*h
+    lagrit_script = f"""
+
+# Figure out which cells (tringles) from DFN full_mesh.inp were not reproduced
+# in the DFM tet fracture faces (facets_f1.inp, facets_f2.inp, etc).
+#
+read / avs / full_mesh.inp / mo_full
+#
+read / avs / facets_merged.inp / mo_merge
+#
+# If the above file exists the next lines can be removed.
+#
+# Interpolate does not work well on coincident 2D triangulations. C'est la vie.
+# To work around this turn the facets into prism volumes by giving them a small
+# negative and positive offset and then combine to make prisms. Then you have volume
+# cells to interpolate from.
+#
+#++++++++++++++++++++++++++++++++++++
+# EPS_OFFSET  should be set to ~0.1h
+#
+define / EPS_OFFSET_1  / {-1*eps_offset}
+define / EPS_OFFSET_2  /  {eps_offset}
+#++++++++++++++++++++++++++++++++++++
+offsetsurf / mo_offset_1 / mo_merge / EPS_OFFSET_1
+cmo / setatt / mo_offset_1 / imt / 1 0 0 / 1
+offsetsurf / mo_offset_2 / mo_merge / EPS_OFFSET_2
+cmo / setatt / mo_offset_2 / imt / 1 0 0 / 2
+addmesh / merge / mo_offset_1_2 / mo_offset_1 / mo_offset_2
+pset / p_bottom / attribute / imt / 1 0 0 / eq / 1
+pset / p_top    / attribute / imt / 1 0 0 / eq / 2
+
+extrude / mo_extrude / mo_offset_1_2 / interp / 0 / &
+        pset,get,p_bottom / pset,get,p_top
+
+cmo / delete / mo_merge
+cmo / delete / mo_offset_1
+cmo / delete / mo_offset_2
+cmo / delete / mo_offset_1_2
+cmo / select / mo_extrude
+quality
+
+cmo / addatt / mo_full / mat_interp / vint / scalar / nelements
+cmo / setatt / mo_full / mat_interp / 1 0 0 / 2
+cmo / setatt / mo_extrude / itetclr / 1 0 0 / 1
+interpolate / map / mo_full mat_interp / 1 0 0 / &
+                    mo_extrude itetclr
+dump / avs / tmp_interpolate.inp / mo_full
+cmo / delete / mo_extrude
+cmo / select / mo_full
+eltset / edelete / mat_interp / eq / 1
+
+cmo / addatt / mo_full / volume / e_area
+math / sum / mo_full / area_sum / 1,0,0 / mo_full / e_area
+
+rmpoint / element /  eltset get edelete
+rmpoint / compress
+# Note: If there are no missed cells, this will return:
+# RMPOINT: new point count is            0                                        
+# RMPOINT: new element count is          0                                        
+
+cmo / status / brief
+
+cmo / addatt / mo_full / volume / e_area
+math / sum / mo_full / area_sum / 1,0,0 / mo_full / e_area
+# Note: If there are no missed cells, this MO will be empty and this
+# command will return:
+# 0 element attribute: e_area
+# FATAL ERROR: SUM unable to begin.
+# error in command : math/sum/mo_full/area_sum/1,0,0/mo_full/e_area
+#
+# The attributes that are output in this file could be cleaned up so
+# extra unnecessary information is not included.
+cmo / DELATT / mo_full / e_area
+cmo / DELATT / mo_full / mat_interp
+#
+# NOTE: If there are no missed cells, mo_full will be an empty (#nodes=0) MO
+# No file will be written and LaGriT message will be:
+# WARNING: dumpavs             
+# WARNING: nnodes=0 nelements = 0
+# WARNING: No output
+dump / avs / missed_cells_full_mesh.inp / mo_full
+
+cmo / delete / mo_full
+
+finish
+
+
+
+"""
+    with open('dfm_diagnostics.mlgi', 'w') as fp:
+        fp.write(lagrit_script)
+        fp.flush()
+
+    print("Creating dfm_diagonstics.mlgi file: Complete\n")
+
+
+def create_dfm():
+    """ This function executes the lagrit scripts. 
+    
+    Parameters
+    ----------
+        None    
+
+    Returns
+    -------
+        None
+    
+    Notes
+    -----
+        None
+ 
+    """
+    # Run LaGriT
+    mh.run_lagrit_script(
+        "dfm_mesh_fracture_driver.lgi",
+        quiet=False)
+
+
+
+def cleanup_mesh_dfm_directory():
+    """ Clean up working files from meshing the DFM
+
+    Parameters
+    ---------------
+        None
+
+    Returns
+    ----------------
+        None
+
+    Notes
+    ---------------
+        None
+
+    """
+    print("--> Cleaning up working directory")
+    # clean up LaGrit Scripts
+    lagrit_script_dir = "dfm_lagrit_files" 
+    try:
+        os.mkdir(lagrit_script_dir)
+    except:
+        shutil.rmtree(lagrit_script_dir)
+        os.mkdir(lagrit_script_dir)
+    lagrit_scripts = glob.glob("*lgi")
+    for filename in lagrit_scripts:
+        shutil.copyfile(filename, lagrit_script_dir + os.sep + filename)
+        os.remove(filename)
+
+    extra_files = ['dfm_mesh_fracture_driver.lgi.log','dfm_mesh_fracture_driver.lgi.out',
+                   'tmp_interpolate.inp']
+    for filename in extra_files:
+        shutil.copyfile(filename, lagrit_script_dir + os.sep + filename)
+        os.remove(filename)
+
+    table_dir = "tables"
+    try:
+        os.mkdir(table_dir)
+    except:
+        shutil.rmtree(table_dir)
+        os.mkdir(table_dir)
+
+    table_files = glob.glob("*table")
+    for filename in table_files:
+        shutil.copyfile(filename, table_dir + os.sep + filename)
+        os.remove(filename)
+
+    facets_dir = "facets"
+    try:
+        os.mkdir(facets_dir)
+    except:
+        shutil.rmtree(facets_dir)
+        os.mkdir(facets_dir)
+
+    facet_files = glob.glob("facets*inp")
+    for filename in facet_files:
+        shutil.copyfile(filename, facets_dir + os.sep + filename)
+        os.remove(filename)
+
+
+    print("--> Cleaning up working directory: Complete")
+
+
+def check_dfm_mesh(allowed_percentage):
+    """ Checks how many elements of the DFN meshing are missinf from the DFM. If the percentage missing is larger than the allowed percentage, then the program exists.
+
+    Parameters
+    ----------------
+        allowed_percentage : float
+            Percentage of the mesh allowed to be missing and still continue
+
+    Returns
+    ----------
+        None
+
+    Notes
+    ----------
+        None
+    
+    """
+
+    print("--> Checking for missing elements")
+    if os.path.isfile('missed_cells_full_mesh.inp'):
+        print("--> Missing elements have been found.")
+        print(f"--> Missing elements are in the file 'missed_cells_full_mesh.inp' if you want to see them.")
+        # get number of missed elements in the 
+        with open('missed_cells_full_mesh.inp', 'r') as fp:
+            line = fp.readline().split()
+            missing_num_elems = int(line[1])
+        # get the total number of elements
+
+        with open('full_mesh.inp', 'r') as fp:
+            line = fp.readline().split()
+            total_num_elems = int(line[1])
+        # Compute percentage and compare
+        missing_percent = 100*(missing_num_elems/total_num_elems)
+        print(f"--> Out of {total_num_elems} elements in the DFN there are {missing_num_elems} missing from the DFM.")
+        print(f"--> That's {missing_percent:0.2f} percent of the mesh.")
+
+        if  missing_percent > allowed_percentage:
+            error = f"*** Error. Missing percent of mesh is larger than tolerance {allowed_percentage} ***\n*** Exitting ***\n "
+            sys.stderr.write(error)
+            sys.exit(1)
+        else:
+            print("--> Doesn't seem to bad. Keep Calm and Carry on.")
+
+    # if the file 'missed_cells_full_mesh.inp' does not exists, this means no elements were missed.  
+    else:
+        print("--> No missinng elements found. ")
+
+
+[docs] +def mesh_dfm(self, dirname = "dfm_mesh", allowed_percentage = 1, psets = False, cleanup = True): + """" Creates a conforming mesh of a DFN using a uniform background tetrahedron mesh. The DFN must be meshed using a uniform triangular mesh. (DFN.mesh_network(uniform_mesh = True)) + + Parameters + ------------------ + dirname : string + name of working directory. Default : dfm_mesh + allowed_percentage : float + Percentage of the mesh allowed to be missing and still continue + cleanup : bool + Clean up working directory. If true dep files are moved into subdirectories + + Returns + --------------- + None + + Notes + -------------- + The final mesh is output in exodus format. This requires that LaGriT is built against exodus. + + """ + + print('=' * 80) + print("Creating conforming DFM mesh using LaGriT : Starting") + print('=' * 80) + + setup_mesh_dfm_directory(self.jobname, dirname) + + center = [self.params['domainCenter']['value'][0],self.params['domainCenter']['value'][1], self.params['domainCenter']['value'][2]] + translate_mesh(center,[0,0,0]) + box_domain, num_points_x, num_points_y, num_points_z = create_domain(self.domain, self.h) + dfm_driver(num_points_x, num_points_y, num_points_z , self.num_frac, self.h, box_domain, psets) + dfm_box(box_domain) + dfm_build() + dfm_fracture_facets(self.num_frac) + dfm_facets() + dfm_diagnostics(self.h) + create_dfm() + + check_dfm_mesh(allowed_percentage) + + translate_mesh([0,0,0], center) + + if cleanup: + cleanup_mesh_dfm_directory() + + print('=' * 80) + print("Creating conforming DFM mesh using LaGriT : Complete") + print('=' * 80)
+ + +
+ +
+
+
+ +
+ +
+

© Copyright 2020, LANL, LA-UR-17-22216.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_modules/pydfnworks/dfnGen/meshing/mapdfn_ecpm/mapdfn_ecpm.html b/docs/_modules/pydfnworks/dfnGen/meshing/mapdfn_ecpm/mapdfn_ecpm.html index e55e9c0f9..324b89f09 100644 --- a/docs/_modules/pydfnworks/dfnGen/meshing/mapdfn_ecpm/mapdfn_ecpm.html +++ b/docs/_modules/pydfnworks/dfnGen/meshing/mapdfn_ecpm/mapdfn_ecpm.html @@ -1,19 +1,21 @@ - + - pydfnworks.dfnGen.meshing.mapdfn_ecpm.mapdfn_ecpm — dfnWorks 2.7 documentation - - + pydfnworks.dfnGen.meshing.mapdfn_ecpm.mapdfn_ecpm — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/_modules/pydfnworks/dfnGen/meshing/mesh_dfn/mesh_dfn.html b/docs/_modules/pydfnworks/dfnGen/meshing/mesh_dfn/mesh_dfn.html index 32b341f08..8ae7c4f1a 100644 --- a/docs/_modules/pydfnworks/dfnGen/meshing/mesh_dfn/mesh_dfn.html +++ b/docs/_modules/pydfnworks/dfnGen/meshing/mesh_dfn/mesh_dfn.html @@ -1,19 +1,21 @@ - + - pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn — dfnWorks 2.7 documentation - - + pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/_modules/pydfnworks/dfnGen/meshing/mesh_dfn/mesh_dfn_helper.html b/docs/_modules/pydfnworks/dfnGen/meshing/mesh_dfn/mesh_dfn_helper.html index 53d2182ae..acd732b12 100644 --- a/docs/_modules/pydfnworks/dfnGen/meshing/mesh_dfn/mesh_dfn_helper.html +++ b/docs/_modules/pydfnworks/dfnGen/meshing/mesh_dfn/mesh_dfn_helper.html @@ -1,19 +1,21 @@ - + - pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn_helper — dfnWorks 2.7 documentation - - + pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn_helper — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
@@ -404,7 +406,7 @@

Source code for pydfnworks.dfnGen.meshing.mesh_dfn.mesh_dfn_helper

hf.print_error(f"LaGriT script {lagrit_file} failed to run properly") else: if not quiet: - print(f"--> LaGriT script {lagrit_file} was run successful") + print(f"--> LaGriT script {lagrit_file} ran successfully") return failure
diff --git a/docs/_modules/pydfnworks/dfnGen/meshing/udfm/false_connections.html b/docs/_modules/pydfnworks/dfnGen/meshing/udfm/false_connections.html index 59d6398cc..194781f30 100644 --- a/docs/_modules/pydfnworks/dfnGen/meshing/udfm/false_connections.html +++ b/docs/_modules/pydfnworks/dfnGen/meshing/udfm/false_connections.html @@ -1,19 +1,21 @@ - + - pydfnworks.dfnGen.meshing.udfm.false_connections — dfnWorks 2.7 documentation - - + pydfnworks.dfnGen.meshing.udfm.false_connections — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/_modules/pydfnworks/dfnGen/meshing/udfm/map2continuum.html b/docs/_modules/pydfnworks/dfnGen/meshing/udfm/map2continuum.html index b073bfc91..433321272 100644 --- a/docs/_modules/pydfnworks/dfnGen/meshing/udfm/map2continuum.html +++ b/docs/_modules/pydfnworks/dfnGen/meshing/udfm/map2continuum.html @@ -1,19 +1,21 @@ - + - pydfnworks.dfnGen.meshing.udfm.map2continuum — dfnWorks 2.7 documentation - - + pydfnworks.dfnGen.meshing.udfm.map2continuum — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
@@ -181,7 +183,12 @@

Source code for pydfnworks.dfnGen.meshing.udfm.map2continuum

if self.num_frac == 1: self.normal_vectors = np.array([self.normal_vectors]) - lagrit_driver(dir_name, nx, ny, nz, self.num_frac, self.normal_vectors,points) + + + center = [self.params['domainCenter']['value'][0],self.params['domainCenter']['value'][1], self.params['domainCenter']['value'][2]] + translate_mesh(center,[0,0,0]) + + lagrit_driver(dir_name, nx, ny, nz, self.num_frac, self.normal_vectors,points, center) #lagrit_driver(dir_name, nx, ny, nz, self.num_frac, self.normal_vectors, # self.centers) @@ -198,10 +205,40 @@

Source code for pydfnworks.dfnGen.meshing.udfm.map2continuum

build_dict(self, self.num_frac, delete_files=True) dir_cleanup() ## set object variable name - self.inp_file = "octree_dfn.inp"
+ self.inp_file = "octree_dfn.inp" + translate_mesh([0,0,0], center)
+ + + +def translate_mesh(x1, x2): + """ + Moves reduced_mesh.inp from center at x1 to x2 + Parameters + --------------- + x1 : list + floats x-0, y-1, z-2 - current center + + x2 : list + floats x-0, y-1, z-2 - requisted center + Returns + -------------- + None + + """ + + lagrit_script = f""" +read / avs / reduced_mesh.inp / MODFN +trans / 1 0 0 / {x1[0]} {x1[1]} {x1[2]} / {x2[0]} {x2[1]} {x2[2]} +dump / reduced_mesh.inp / MODFN +finish +""" + with open('translate_mesh.lgi', 'w') as fp: + fp.write(lagrit_script) + fp.flush() + mh.run_lagrit_script("translate_mesh.lgi") -def lagrit_driver(dir_name, nx, ny, nz, num_poly, normal_vectors, points): +def lagrit_driver(dir_name, nx, ny, nz, num_poly, normal_vectors, points, center): """ This function creates the main lagrit driver script, which calls all lagrit scripts. @@ -334,7 +371,7 @@

Source code for pydfnworks.dfnGen.meshing.udfm.map2continuum

f_name = f'{dir_name}/driver_octree_start.lgi' f = open(f_name, 'w') - fin = ("""# + fin = (f"""# # LaGriT control files to build an octree refined hex mesh with refinement # based on intersection of hex mesh with a DFN triangulation mesh # @@ -462,6 +499,10 @@

Source code for pydfnworks.dfnGen.meshing.udfm.map2continuum

pset / back_s / attribute / yic / 1 0 0 / lt / YMIN pset / back_s / zone / FOUT / ascii / ZONE + +trans / 1 0 0 / 0. 0. 0. / {center[0]}, {center[1]}, {center[2]} + + dump / pflotran / full_mesh / MOTET / nofilter_zero dump / avs2 / octree_dfn.inp / MOTET dump / coord / octree_dfn / MOTET diff --git a/docs/_modules/pydfnworks/dfnGen/meshing/udfm/upscale.html b/docs/_modules/pydfnworks/dfnGen/meshing/udfm/upscale.html index 14615e807..31d1028b5 100644 --- a/docs/_modules/pydfnworks/dfnGen/meshing/udfm/upscale.html +++ b/docs/_modules/pydfnworks/dfnGen/meshing/udfm/upscale.html @@ -1,19 +1,21 @@ - + - pydfnworks.dfnGen.meshing.udfm.upscale — dfnWorks 2.7 documentation - - + pydfnworks.dfnGen.meshing.udfm.upscale — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/_modules/pydfnworks/dfnGen/well_package/wells.html b/docs/_modules/pydfnworks/dfnGen/well_package/wells.html index 288211497..8b875de4e 100644 --- a/docs/_modules/pydfnworks/dfnGen/well_package/wells.html +++ b/docs/_modules/pydfnworks/dfnGen/well_package/wells.html @@ -1,19 +1,21 @@ - + - pydfnworks.dfnGen.well_package.wells — dfnWorks 2.7 documentation - - + pydfnworks.dfnGen.well_package.wells — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/_modules/pydfnworks/dfnGraph/dfn2graph.html b/docs/_modules/pydfnworks/dfnGraph/dfn2graph.html index fdd0019bd..a3d9419c0 100644 --- a/docs/_modules/pydfnworks/dfnGraph/dfn2graph.html +++ b/docs/_modules/pydfnworks/dfnGraph/dfn2graph.html @@ -1,19 +1,21 @@ - + - pydfnworks.dfnGraph.dfn2graph — dfnWorks 2.7 documentation - - + pydfnworks.dfnGraph.dfn2graph — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/_modules/pydfnworks/dfnGraph/graph_flow.html b/docs/_modules/pydfnworks/dfnGraph/graph_flow.html index 0386f3365..4db88722d 100644 --- a/docs/_modules/pydfnworks/dfnGraph/graph_flow.html +++ b/docs/_modules/pydfnworks/dfnGraph/graph_flow.html @@ -1,19 +1,21 @@ - + - pydfnworks.dfnGraph.graph_flow — dfnWorks 2.7 documentation - - + pydfnworks.dfnGraph.graph_flow — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
@@ -379,7 +381,27 @@

Source code for pydfnworks.dfnGraph.graph_flow

return p32, dQ, Qf -def dump_graph_flow_values(G): +def dump_graph_flow_values(G,graph_flow_filename): + """ + Writes graph flow information to an h5 file named graph_flow_name. + + Parameters + -------------------- + G : NetworkX graph + graph with flow variables attached + + graph_flow_filename : string + name of output file + + Returns + --------------- + None + + Notes + --------------- + name of graph_flow_filename is set in run_graph_flow for primary workflow. Default is graph_flow.hdf5 + + """ num_edges = G.number_of_edges() velocity = np.zeros(num_edges) @@ -398,7 +420,8 @@

Source code for pydfnworks.dfnGraph.graph_flow

aperture[i] = d['b'] volume[i] = area[i] * aperture[i] - with h5py.File(f"graph_flow.hdf5", "w") as f5file: + print(f"--> Writting flow solution to filename: {graph_flow_filename}") + with h5py.File(graph_flow_filename, "w") as f5file: h5dset = f5file.create_dataset('velocity', data=velocity) h5dset = f5file.create_dataset('length', data=lengths) h5dset = f5file.create_dataset('vol_flow_rate', data=vol_flow_rate) @@ -417,7 +440,8 @@

Source code for pydfnworks.dfnGraph.graph_flow

pressure_out, fluid_viscosity=8.9e-4, phi=1, - G=None): + G=None, + graph_flow_name = "graph_flow.hdf5"): """ Solve for pressure driven steady state flow on a graph representation of the DFN. Parameters @@ -458,7 +482,7 @@

Source code for pydfnworks.dfnGraph.graph_flow

Gtilde = solve_flow_on_graph(Gtilde, pressure_in, pressure_out, fluid_viscosity, phi) - dump_graph_flow_values(Gtilde) + dump_graph_flow_values(Gtilde, graph_flow_name) return Gtilde

diff --git a/docs/_modules/pydfnworks/dfnGraph/graph_transport.html b/docs/_modules/pydfnworks/dfnGraph/graph_transport.html index 0a3379def..187f62104 100644 --- a/docs/_modules/pydfnworks/dfnGraph/graph_transport.html +++ b/docs/_modules/pydfnworks/dfnGraph/graph_transport.html @@ -1,19 +1,21 @@ - + - pydfnworks.dfnGraph.graph_transport — dfnWorks 2.7 documentation - - + pydfnworks.dfnGraph.graph_transport — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/_modules/pydfnworks/dfnGraph/pruning.html b/docs/_modules/pydfnworks/dfnGraph/pruning.html index 9642f8ba8..57a90598a 100644 --- a/docs/_modules/pydfnworks/dfnGraph/pruning.html +++ b/docs/_modules/pydfnworks/dfnGraph/pruning.html @@ -1,19 +1,21 @@ - + - pydfnworks.dfnGraph.pruning — dfnWorks 2.7 documentation - - + pydfnworks.dfnGraph.pruning — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/_modules/pydfnworks/dfnTrans/transport.html b/docs/_modules/pydfnworks/dfnTrans/transport.html index 59bd1e604..8deddcf24 100644 --- a/docs/_modules/pydfnworks/dfnTrans/transport.html +++ b/docs/_modules/pydfnworks/dfnTrans/transport.html @@ -1,19 +1,21 @@ - + - pydfnworks.dfnTrans.transport — dfnWorks 2.7 documentation - - + pydfnworks.dfnTrans.transport — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/_static/basic.css b/docs/_static/basic.css index 30fee9d0f..f316efcb4 100644 --- a/docs/_static/basic.css +++ b/docs/_static/basic.css @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- basic theme. * - * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/docs/_static/doctools.js b/docs/_static/doctools.js index d06a71d75..4d67807d1 100644 --- a/docs/_static/doctools.js +++ b/docs/_static/doctools.js @@ -4,7 +4,7 @@ * * Base JavaScript utilities for all Sphinx HTML documentation. * - * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/docs/_static/documentation_options.js b/docs/_static/documentation_options.js index 0e1fafab6..f53cd810e 100644 --- a/docs/_static/documentation_options.js +++ b/docs/_static/documentation_options.js @@ -1,5 +1,5 @@ const DOCUMENTATION_OPTIONS = { - VERSION: '2.7', + VERSION: 'v2.8', LANGUAGE: 'en', COLLAPSE_INDEX: false, BUILDER: 'html', diff --git a/docs/_static/language_data.js b/docs/_static/language_data.js index 250f5665f..367b8ed81 100644 --- a/docs/_static/language_data.js +++ b/docs/_static/language_data.js @@ -5,7 +5,7 @@ * This script contains the language-specific data used by searchtools.js, * namely the list of stopwords, stemmer, scorer and splitter. * - * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @@ -13,7 +13,7 @@ var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; -/* Non-minified version is copied as a separate JS file, is available */ +/* Non-minified version is copied as a separate JS file, if available */ /** * Porter Stemmer diff --git a/docs/_static/searchtools.js b/docs/_static/searchtools.js index 7918c3fab..92da3f8b2 100644 --- a/docs/_static/searchtools.js +++ b/docs/_static/searchtools.js @@ -4,7 +4,7 @@ * * Sphinx JavaScript utilities for the full-text search. * - * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @@ -99,7 +99,7 @@ const _displayItem = (item, searchTerms, highlightTerms) => { .then((data) => { if (data) listItem.appendChild( - Search.makeSearchSummary(data, searchTerms) + Search.makeSearchSummary(data, searchTerms, anchor) ); // highlight search terms in the summary if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js @@ -116,8 +116,8 @@ const _finishSearch = (resultCount) => { ); else Search.status.innerText = _( - `Search finished, found ${resultCount} page(s) matching the search query.` - ); + "Search finished, found ${resultCount} page(s) matching the search query." + ).replace('${resultCount}', resultCount); }; const _displayNextItem = ( results, @@ -137,6 +137,22 @@ const _displayNextItem = ( // search finished, update title and status message else _finishSearch(resultCount); }; +// Helper function used by query() to order search results. +// Each input is an array of [docname, title, anchor, descr, score, filename]. +// Order the results by score (in opposite order of appearance, since the +// `_displayNextItem` function uses pop() to retrieve items) and then alphabetically. +const _orderResultsByScoreThenName = (a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; +}; /** * Default splitQuery function. Can be overridden in ``sphinx.search`` with a @@ -160,13 +176,26 @@ const Search = { _queued_query: null, _pulse_status: -1, - htmlToText: (htmlString) => { + htmlToText: (htmlString, anchor) => { const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); - htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); + for (const removalQuery of [".headerlinks", "script", "style"]) { + htmlElement.querySelectorAll(removalQuery).forEach((el) => { el.remove() }); + } + if (anchor) { + const anchorContent = htmlElement.querySelector(`[role="main"] ${anchor}`); + if (anchorContent) return anchorContent.textContent; + + console.warn( + `Anchored content block not found. Sphinx search tries to obtain it via DOM query '[role=main] ${anchor}'. Check your theme or template.` + ); + } + + // if anchor not specified or not found, fall back to main content const docContent = htmlElement.querySelector('[role="main"]'); - if (docContent !== undefined) return docContent.textContent; + if (docContent) return docContent.textContent; + console.warn( - "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." + "Content block not found. Sphinx search tries to obtain it via DOM query '[role=main]'. Check your theme or template." ); return ""; }, @@ -239,16 +268,7 @@ const Search = { else Search.deferQuery(query); }, - /** - * execute search (requires search index to be loaded) - */ - query: (query) => { - const filenames = Search._index.filenames; - const docNames = Search._index.docnames; - const titles = Search._index.titles; - const allTitles = Search._index.alltitles; - const indexEntries = Search._index.indexentries; - + _parseQuery: (query) => { // stem the search terms and add them to the correct list const stemmer = new Stemmer(); const searchTerms = new Set(); @@ -284,16 +304,32 @@ const Search = { // console.info("required: ", [...searchTerms]); // console.info("excluded: ", [...excludedTerms]); - // array of [docname, title, anchor, descr, score, filename] - let results = []; + return [query, searchTerms, excludedTerms, highlightTerms, objectTerms]; + }, + + /** + * execute search (requires search index to be loaded) + */ + _performSearch: (query, searchTerms, excludedTerms, highlightTerms, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // Collect multiple result groups to be sorted separately and then ordered. + // Each is an array of [docname, title, anchor, descr, score, filename]. + const normalResults = []; + const nonMainIndexResults = []; + _removeChildren(document.getElementById("search-progress")); - const queryLower = query.toLowerCase(); + const queryLower = query.toLowerCase().trim(); for (const [title, foundTitles] of Object.entries(allTitles)) { - if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { + if (title.toLowerCase().trim().includes(queryLower) && (queryLower.length >= title.length/2)) { for (const [file, id] of foundTitles) { let score = Math.round(100 * queryLower.length / title.length) - results.push([ + normalResults.push([ docNames[file], titles[file] !== title ? `${titles[file]} > ${title}` : title, id !== null ? "#" + id : "", @@ -308,46 +344,47 @@ const Search = { // search for explicit entries in index directives for (const [entry, foundEntries] of Object.entries(indexEntries)) { if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { - for (const [file, id] of foundEntries) { - let score = Math.round(100 * queryLower.length / entry.length) - results.push([ + for (const [file, id, isMain] of foundEntries) { + const score = Math.round(100 * queryLower.length / entry.length); + const result = [ docNames[file], titles[file], id ? "#" + id : "", null, score, filenames[file], - ]); + ]; + if (isMain) { + normalResults.push(result); + } else { + nonMainIndexResults.push(result); + } } } } // lookup as object objectTerms.forEach((term) => - results.push(...Search.performObjectSearch(term, objectTerms)) + normalResults.push(...Search.performObjectSearch(term, objectTerms)) ); // lookup as search terms in fulltext - results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + normalResults.push(...Search.performTermsSearch(searchTerms, excludedTerms)); // let the scorer override scores with a custom scoring function - if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); - - // now sort the results by score (in opposite order of appearance, since the - // display function below uses pop() to retrieve items) and then - // alphabetically - results.sort((a, b) => { - const leftScore = a[4]; - const rightScore = b[4]; - if (leftScore === rightScore) { - // same score: sort alphabetically - const leftTitle = a[1].toLowerCase(); - const rightTitle = b[1].toLowerCase(); - if (leftTitle === rightTitle) return 0; - return leftTitle > rightTitle ? -1 : 1; // inverted is intentional - } - return leftScore > rightScore ? 1 : -1; - }); + if (Scorer.score) { + normalResults.forEach((item) => (item[4] = Scorer.score(item))); + nonMainIndexResults.forEach((item) => (item[4] = Scorer.score(item))); + } + + // Sort each group of results by score and then alphabetically by name. + normalResults.sort(_orderResultsByScoreThenName); + nonMainIndexResults.sort(_orderResultsByScoreThenName); + + // Combine the result groups in (reverse) order. + // Non-main index entries are typically arbitrary cross-references, + // so display them after other results. + let results = [...nonMainIndexResults, ...normalResults]; // remove duplicate search results // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept @@ -361,7 +398,12 @@ const Search = { return acc; }, []); - results = results.reverse(); + return results.reverse(); + }, + + query: (query) => { + const [searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms] = Search._parseQuery(query); + const results = Search._performSearch(searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms); // for debugging //Search.lastresults = results.slice(); // a copy @@ -466,14 +508,18 @@ const Search = { // add support for partial matches if (word.length > 2) { const escapedWord = _escapeRegExp(word); - Object.keys(terms).forEach((term) => { - if (term.match(escapedWord) && !terms[word]) - arr.push({ files: terms[term], score: Scorer.partialTerm }); - }); - Object.keys(titleTerms).forEach((term) => { - if (term.match(escapedWord) && !titleTerms[word]) - arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); - }); + if (!terms.hasOwnProperty(word)) { + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + } + if (!titleTerms.hasOwnProperty(word)) { + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: titleTerms[term], score: Scorer.partialTitle }); + }); + } } // no match but word was a required one @@ -496,9 +542,8 @@ const Search = { // create the mapping files.forEach((file) => { - if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) - fileMap.get(file).push(word); - else fileMap.set(file, [word]); + if (!fileMap.has(file)) fileMap.set(file, [word]); + else if (fileMap.get(file).indexOf(word) === -1) fileMap.get(file).push(word); }); }); @@ -549,8 +594,8 @@ const Search = { * search summary for a given text. keywords is a list * of stemmed words. */ - makeSearchSummary: (htmlText, keywords) => { - const text = Search.htmlToText(htmlText); + makeSearchSummary: (htmlText, keywords, anchor) => { + const text = Search.htmlToText(htmlText, anchor); if (text === "") return null; const textLower = text.toLowerCase(); diff --git a/docs/applications.html b/docs/applications.html index 55ab3cdff..2a46eb66f 100644 --- a/docs/applications.html +++ b/docs/applications.html @@ -1,20 +1,22 @@ - + - + - Example Applications — dfnWorks 2.7 documentation - - + Example Applications — dfnWorks v2.8 documentation + + + + - - + + @@ -36,7 +38,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
@@ -100,7 +102,8 @@

Example ApplicationsCarbon dioxide sequestration

dfnWorks provides the framework necessary to perform multiphase simulations (such as flow and reactive transport) at the reservoir scale. A particular application, highlighted here, is sequestering CO2 from anthropogenic sources and disposing it in geological formations such as deep saline aquifers and abandoned oil fields. Geological CO2 sequestration is one of the principal methods under consideration to reduce carbon footprint in the atmosphere due to fossil fuels (Bachu, 2002; Pacala and Socolow, 2004). For safe and sustainable long-term storage of CO2 and to prevent leaks through existing faults and fractured rock (along with the ones created during the injection process), understanding the complex physical and chemical interactions between CO2 , water (or brine) and fractured rock, is vital. dfnWorks capability to study multiphase flow in a DFN can be used to study potential CO2 migration through cap-rock, a potential risk associated with proposed subsurface storage of CO2 in saline aquifers or depleted reservoirs. Moreover, using the reactive transport capabilities of PFLOTRAN coupled with cell-based transmissivity of the DFN allows one to study dynamically changing permeability fields with mineral precipitation and dissolution due to CO2 –water interaction with rock.

-alternate text +alternate text +

Temporal evolution of supercritical |CO2| displacing water in a meter cube DFN containing 24 fractures. The DFN is initially fully saturated with water, (top left time 0 hours) and supercritical |CO2| is slowly injected into the system from the bottom of the domain to displace the water for a total time of 10 h. There is an initial flush through the system during the first hour of the simulation, and then the rate of displacement decreases.

@@ -110,7 +113,8 @@

Carbon dioxide sequestration

Hydraulic fracturing (fracking) has provided access to hydrocarbon trapped in low-permeability media, such as tight shales. The process involves injecting water at high pressures to reactivate existing fractures and also create new fractures to increase permeability of the shale allowing hydrocarbons to be extracted. However, the fundamental physics of why fracking works and its long term ramifications are not well understood. Karra et al. (2015) used dfnWorks to generate a typical production site and simulate production. Using this physics based model, they found good agreement with production field data and determined what physical mechanisms control the decline in the production curve.

-alternate text +alternate text +

Pressure in a well used for hydraulic fracturing.

@@ -121,7 +125,8 @@

Nuclear waste repository -alternate text +alternate text +

Simulated particle trajectories in fractured granite at Forsmark, Sweden.

diff --git a/docs/dfnflow.html b/docs/dfnflow.html index 3d3048ebb..27109233f 100644 --- a/docs/dfnflow.html +++ b/docs/dfnflow.html @@ -1,20 +1,22 @@ - + - + - dfnFlow — dfnWorks 2.7 documentation - - + dfnFlow — dfnWorks v2.8 documentation + + + + - - + + @@ -36,7 +38,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/dfngen.html b/docs/dfngen.html index 034dc3086..8dad0b0b2 100644 --- a/docs/dfngen.html +++ b/docs/dfngen.html @@ -1,20 +1,22 @@ - + - + - dfnGen - C++ Generation Code — dfnWorks 2.7 documentation - - + dfnGen - C++ Generation Code — dfnWorks v2.8 documentation + + + + - - + + @@ -36,7 +38,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/dfntrans.html b/docs/dfntrans.html index 214a7fc1c..c2320f149 100644 --- a/docs/dfntrans.html +++ b/docs/dfntrans.html @@ -1,20 +1,22 @@ - + - + - dfnTrans — dfnWorks 2.7 documentation - - + dfnTrans — dfnWorks v2.8 documentation + + + + - - + + @@ -36,7 +38,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/examples.html b/docs/examples.html index b49db5b1c..70ee6a791 100644 --- a/docs/examples.html +++ b/docs/examples.html @@ -1,20 +1,22 @@ - + - + - Examples — dfnWorks 2.7 documentation - - + Examples — dfnWorks v2.8 documentation + + + + - - + + @@ -36,7 +38,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
@@ -105,7 +107,8 @@

4_user_defined_rects -alternate text +alternate text +

The meshed network of four rectangular fractures.

@@ -124,7 +127,8 @@

4_user_defined_ell_uniform -alternate text +alternate text +

The uniformly meshed network of four circular fractures.

@@ -135,7 +139,8 @@

exp: Exponentially Distributed fracture lengths -alternate text +alternate text +

Pressure solution on with rectangular fractures whose lengths following a exponential distribution. Gradient is aligned with the Y-Axis

@@ -146,7 +151,8 @@

TPL: Truncated Power-Law -alternate text +alternate text +

@@ -154,13 +160,15 @@

Graph-based pruninghttps://networkx.github.io/). The second meshes the DFN corresponding to the 2-core of the graph and then runs flow and transport. The 2 core network is in a sub-directory 2-core. The original network has 207 fractures and the 2-core has 79 fractures.

-alternate text +alternate text +

(left) Graph based on DFN topology. Each vertex is a fracture in the network. The inflow boundary is colored blue and the outflow is colored red. (right) 2-Core of the graph to the left.

-alternate text +alternate text +

(left) Original DFN (right) DFN corresponding to the 2-core of the DFN to the left.

diff --git a/docs/gallery.html b/docs/gallery.html index 2f62466eb..ffbd18457 100644 --- a/docs/gallery.html +++ b/docs/gallery.html @@ -1,20 +1,22 @@ - + - + - dfnWorks Gallery — dfnWorks 2.7 documentation - - + dfnWorks Gallery — dfnWorks v2.8 documentation + + + + - - + + @@ -35,7 +37,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/genindex.html b/docs/genindex.html index d8487e319..722d14de7 100644 --- a/docs/genindex.html +++ b/docs/genindex.html @@ -1,19 +1,21 @@ - + - Index — dfnWorks 2.7 documentation - - + Index — dfnWorks v2.8 documentation + + + + - - + + @@ -33,7 +35,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/index_docs.html b/docs/index_docs.html index 8cff65188..8ecc96643 100644 --- a/docs/index_docs.html +++ b/docs/index_docs.html @@ -1,20 +1,22 @@ - + - + - Welcome to dfnWorks 2.8 documentation! — dfnWorks 2.7 documentation - - + Welcome to dfnWorks 2.8 documentation! — dfnWorks v2.8 documentation + + + + - - + + @@ -35,7 +37,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/intro.html b/docs/intro.html index e20fef4a8..7cf2da154 100644 --- a/docs/intro.html +++ b/docs/intro.html @@ -1,20 +1,22 @@ - + - + - Welcome To dfnWorks — dfnWorks 2.7 documentation - - + Welcome To dfnWorks — dfnWorks v2.8 documentation + + + + - - + + @@ -36,7 +38,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/objects.inv b/docs/objects.inv index 86779310f..eea33c7a7 100644 Binary files a/docs/objects.inv and b/docs/objects.inv differ diff --git a/docs/output.html b/docs/output.html index d144c8c8e..e859d897f 100644 --- a/docs/output.html +++ b/docs/output.html @@ -1,20 +1,22 @@ - + - + - Run Files — dfnWorks 2.7 documentation - - + Run Files — dfnWorks v2.8 documentation + + + + - - + + @@ -36,7 +38,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/publications.html b/docs/publications.html index 02f8bdb69..7289c34c5 100644 --- a/docs/publications.html +++ b/docs/publications.html @@ -1,20 +1,22 @@ - + - + - dfnWorks Publications — dfnWorks 2.7 documentation - - + dfnWorks Publications — dfnWorks v2.8 documentation + + + + - - + + @@ -36,7 +38,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/py-modindex.html b/docs/py-modindex.html index 12a362db1..6713dec36 100644 --- a/docs/py-modindex.html +++ b/docs/py-modindex.html @@ -1,19 +1,21 @@ - + - Python Module Index — dfnWorks 2.7 documentation - - + Python Module Index — dfnWorks v2.8 documentation + + + + - - + + @@ -36,7 +38,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
diff --git a/docs/pydfnFlow.html b/docs/pydfnFlow.html index 5108427c1..09a731b57 100644 --- a/docs/pydfnFlow.html +++ b/docs/pydfnFlow.html @@ -1,20 +1,22 @@ - + - + - pydfnworks: dfnFlow — dfnWorks 2.7 documentation - - + pydfnworks: dfnFlow — dfnWorks v2.8 documentation + + + + - - + + @@ -36,7 +38,7 @@
- 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
@@ -278,7 +280,7 @@
  • self (object) – DFN Class

  • zone_file (string) – Name of zone file

  • -
  • Face (Face of the plane corresponding to the zone file) –

  • +
  • Face (Face of the plane corresponding to the zone file)

  • zone_file – Name of zone file to work on. Can be ‘all’ processes all directions, top, bottom, left, right, front, back

  • boundary_cell_area (double) – should be a large value relative to the mesh size to force pressure boundary conditions.

@@ -331,7 +333,7 @@

Processing Flow

-effective_perm(self, inflow_pressure, outflow_pressure, boundary_file, direction)[source]
+effective_perm(self, inflow_pressure, outflow_pressure, boundary_file, direction, darcy_vel_file='darcyvel.dat')[source]

Computes the effective permeability of a DFN in the primary direction of flow using a steady-state PFLOTRAN solution.

Parameters:
@@ -341,6 +343,7 @@
  • outflow_pressure (float) – Pressure at the outflow boundary face. Units are Pascal

  • boundary_file (string) – Name of inflow boundary file, e.g., pboundary_left.ex

  • direction (string) – Primary direction of flow, x, y, or z

  • +
  • darcy_vel_file (string) – Name of concatenated Darcy velocity file

  • Return type:
    diff --git a/docs/pydfnGen.html b/docs/pydfnGen.html index 3e1269932..2aab08f0f 100644 --- a/docs/pydfnGen.html +++ b/docs/pydfnGen.html @@ -1,20 +1,22 @@ - + - + - pydfnworks: dfnGen — dfnWorks 2.7 documentation - - + pydfnworks: dfnGen — dfnWorks v2.8 documentation + + + + - - + + @@ -36,7 +38,7 @@
    - 2.7, LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027 + 2.8 LANL, Docs: LA-UR-17-22216, Software: LA-CC-17-027
    @@ -169,34 +171,34 @@

    Adding Fracture Families
    Parameters: