From fa217b639f7d8e716a5d17c5550f5bb16ca01b0a Mon Sep 17 00:00:00 2001 From: Jannik Buhr Date: Mon, 6 Nov 2023 13:46:38 +0100 Subject: [PATCH] render docs --- _reference/cmd.qmd | 5 +- _reference/config.qmd | 4 +- _reference/parsing.qmd | 4 - _reference/plugins.qmd | 4 +- _reference/recipe.qmd | 18 +- _reference/runmanager.qmd | 4 +- _reference/tasks.qmd | 19 - _reference/topology.topology.qmd | 14 +- docs/_reference/analysis.html | 204 +++- docs/_reference/cmd.html | 206 +++- docs/_reference/config.html | 208 +++- docs/_reference/constants.html | 204 +++- docs/_reference/coordinates.html | 204 +++- .../dummyreaction.reaction.DummyReaction.html | 202 +++- .../hat_naive.reaction.NaiveHAT.html | 204 +++- .../homolysis.reaction.Homolysis.html | 204 +++- docs/_reference/index.html | 208 +++- docs/_reference/kmc.html | 204 +++- docs/_reference/parsing.TopologyDict.html | 204 +++- docs/_reference/parsing.html | 207 +++- docs/_reference/plugins.html | 208 +++- docs/_reference/recipe.html | 222 ++-- docs/_reference/runmanager.html | 208 +++- docs/_reference/schema.html | 200 +++- docs/_reference/tasks.html | 210 ++-- docs/_reference/tools.html | 204 +++- docs/_reference/topology.atomic.html | 204 +++- docs/_reference/topology.ff.html | 204 +++- docs/_reference/topology.topology.html | 218 ++-- docs/_reference/topology.utils.html | 204 +++- docs/_reference/utils.html | 204 +++- docs/guide/explanation/index.html | 209 +++- docs/guide/how_to/contribute.html | 210 +++- docs/guide/how_to/hcp.html | 213 ++-- docs/guide/how_to/index.html | 215 ++-- docs/guide/how_to/options.html | 275 +++-- docs/guide/how_to/plugins.html | 210 +++- docs/guide/how_to/topology.html | 379 ++++--- docs/guide/index.html | 203 +++- docs/guide/tutorials/colbuilder.html | 216 ++-- docs/guide/tutorials/getting-started.html | 216 ++-- docs/guide/tutorials/index.html | 215 ++-- docs/guide/tutorials/write-plugin.html | 225 ++-- docs/index.html | 200 +++- docs/search.json | 973 ++++++++++++------ .../bootstrap/bootstrap-dark.min.css | 10 +- docs/site_libs/bootstrap/bootstrap-icons.css | 101 +- docs/site_libs/bootstrap/bootstrap-icons.woff | Bin 164360 -> 176200 bytes docs/site_libs/bootstrap/bootstrap.min.css | 10 +- docs/site_libs/bootstrap/bootstrap.min.js | 6 +- docs/site_libs/quarto-html/quarto.js | 13 - docs/site_libs/quarto-search/quarto-search.js | 109 +- docs/sitemap.xml | 136 +-- 53 files changed, 6581 insertions(+), 2580 deletions(-) diff --git a/_reference/cmd.qmd b/_reference/cmd.qmd index 843075e7..c8cd8b16 100644 --- a/_reference/cmd.qmd +++ b/_reference/cmd.qmd @@ -34,7 +34,8 @@ Run KIMMDY from the command line. The configuration is gathered from the input file, which is `kimmdy.yml` by default. -See [](`~kimmdy.cmd.get_cmdline_args`) or `kimmdy --help` for the descriptions of the arguments. +See [](`~kimmdy.cmd.get_cmdline_args`) or `kimmdy --help` +for the descriptions of the arguments. ### get_cmdline_args { #kimmdy.cmd.get_cmdline_args } @@ -50,7 +51,7 @@ Parse command line arguments. ### kimmdy_run { #kimmdy.cmd.kimmdy_run } -`cmd.kimmdy_run(input=Path('kimmdy.yml'), loglevel=None, logfile=None, checkpoint='', show_plugins=False, show_schema_path=False, generate_jobscript=False, debug=False)` +`cmd.kimmdy_run(input=Path('kimmdy.yml'), loglevel=None, logfile=None, checkpoint='', show_plugins=False, show_schema_path=False, generate_jobscript=False, debug=False, callgraph=False)` Run KIMMDY from python. diff --git a/_reference/config.qmd b/_reference/config.qmd index 43a7131b..aad49756 100644 --- a/_reference/config.qmd +++ b/_reference/config.qmd @@ -37,13 +37,13 @@ and computationally expensive operations. ##### attr { #kimmdy.config.Config.attr } -`config.Config.attr(attribute)` +`config.Config.attr(self, attribute)` Get the value of a specific attribute. Alias for self.__getattribute__ ##### get_attributes { #kimmdy.config.Config.get_attributes } -`config.Config.get_attributes()` +`config.Config.get_attributes(self)` Get a list of all attributes without hidden ones (_<...>). \ No newline at end of file diff --git a/_reference/parsing.qmd b/_reference/parsing.qmd index 58717729..0c98a94f 100644 --- a/_reference/parsing.qmd +++ b/_reference/parsing.qmd @@ -224,10 +224,6 @@ raw_top = `parsing.resolve_includes(path, gmx_builtin_ffs=None)` -Resolve #include statements in a (top/itp) file. - - - #### Arguments path : diff --git a/_reference/plugins.qmd b/_reference/plugins.qmd index 779864b4..37d743da 100644 --- a/_reference/plugins.qmd +++ b/_reference/plugins.qmd @@ -27,7 +27,7 @@ reconstruct base force field state ##### parameterize_topology { #kimmdy.plugins.BasicParameterizer.parameterize_topology } -`plugins.BasicParameterizer.parameterize_topology(current_topology)` +`plugins.BasicParameterizer.parameterize_topology(self, current_topology)` Do nothing, all necessary actions should already have happened in bind_bond and break_bond of Topology @@ -53,7 +53,7 @@ Reaction base class ##### get_recipe_collection { #kimmdy.plugins.ReactionPlugin.get_recipe_collection } -`plugins.ReactionPlugin.get_recipe_collection(files)` +`plugins.ReactionPlugin.get_recipe_collection(self, files)` Get a RecipeCollection as a result of the reaction. diff --git a/_reference/recipe.qmd b/_reference/recipe.qmd index 3225123f..75191dd1 100644 --- a/_reference/recipe.qmd +++ b/_reference/recipe.qmd @@ -114,7 +114,7 @@ product state from the educt state. ##### calc_averages { #kimmdy.recipe.Recipe.calc_averages } -`recipe.Recipe.calc_averages(window_size)` +`recipe.Recipe.calc_averages(self, window_size)` Calulate average rates over some window size @@ -126,13 +126,13 @@ Calulate average rates over some window size ##### check_consistency { #kimmdy.recipe.Recipe.check_consistency } -`recipe.Recipe.check_consistency()` +`recipe.Recipe.check_consistency(self)` Run consistency checks for correct size of variables ##### combine_with { #kimmdy.recipe.Recipe.combine_with } -`recipe.Recipe.combine_with(other)` +`recipe.Recipe.combine_with(self, other)` Combines this Recipe with another with the same RecipeSteps. @@ -168,13 +168,13 @@ They can originate from multiple reaction plugins, but do not need to. ##### aggregate_reactions { #kimmdy.recipe.RecipeCollection.aggregate_reactions } -`recipe.RecipeCollection.aggregate_reactions()` +`recipe.RecipeCollection.aggregate_reactions(self)` Combines reactions having the same sequence of RecipeSteps. ##### calc_cumprob { #kimmdy.recipe.RecipeCollection.calc_cumprob } -`recipe.RecipeCollection.calc_cumprob()` +`recipe.RecipeCollection.calc_cumprob(self)` Calculate cumulative probability of all contained recipe steps. Sums up to 1 over all recipes. Assumes constant rate for given timespan @@ -182,7 +182,7 @@ and rate zero otherwise. ##### calc_ratesum { #kimmdy.recipe.RecipeCollection.calc_ratesum } -`recipe.RecipeCollection.calc_ratesum()` +`recipe.RecipeCollection.calc_ratesum(self)` Calculate the sum of rates over all timesteps @@ -196,14 +196,14 @@ Calculate the sum of rates over all timesteps ##### from_csv { #kimmdy.recipe.RecipeCollection.from_csv } -`recipe.RecipeCollection.from_csv(path)` +`recipe.RecipeCollection.from_csv(cls, path)` Create a RecipeCollection object from a CSV file Returns the recipe collection and a single recipe that was picked, otherwise None ##### plot { #kimmdy.recipe.RecipeCollection.plot } -`recipe.RecipeCollection.plot(outfile, highlight_r=None, highlight_t=None)` +`recipe.RecipeCollection.plot(self, outfile, highlight_r=None, highlight_t=None)` Plot reaction rates over time @@ -217,7 +217,7 @@ Plot reaction rates over time ##### to_csv { #kimmdy.recipe.RecipeCollection.to_csv } -`recipe.RecipeCollection.to_csv(path, picked_recipe=None)` +`recipe.RecipeCollection.to_csv(self, path, picked_recipe=None)` Write a ReactionResult as defined in the reaction module to a csv file diff --git a/_reference/runmanager.qmd b/_reference/runmanager.qmd index bfe58c5b..dc429bce 100644 --- a/_reference/runmanager.qmd +++ b/_reference/runmanager.qmd @@ -51,7 +51,7 @@ rest of the program and keeps track of global state. ##### get_latest { #kimmdy.runmanager.RunManager.get_latest } -`runmanager.RunManager.get_latest(suffix)` +`runmanager.RunManager.get_latest(self, suffix)` Returns path to latest file of given type. @@ -60,7 +60,7 @@ Errors if file is not found. ##### write_one_checkpoint { #kimmdy.runmanager.RunManager.write_one_checkpoint } -`runmanager.RunManager.write_one_checkpoint()` +`runmanager.RunManager.write_one_checkpoint(self)` Just write the first checkpoint and then exit diff --git a/_reference/tasks.qmd b/_reference/tasks.qmd index 77aa44fb..566636a3 100644 --- a/_reference/tasks.qmd +++ b/_reference/tasks.qmd @@ -23,14 +23,6 @@ Dictionary that gets populated by calling get_missing. `tasks.Task(self, runmng, f, kwargs=None, out=None)` -A task to be performed as as a step in the RunManager. - -A task consists of a function and its keyword arguments. -Calling a taks calls the stored function. -The function must return a TaskFiles object. - - - #### Parameters: runmng @@ -46,17 +38,6 @@ out `tasks.TaskFiles(get_latest, input=field(default_factory=dict), output=field(default_factory=dict), outputdir=Path(), logger=logging.getLogger('kimmdy.basetask'))` -Class for Task input and output files and directories. - -Hosts the input and output file paths belonging to a task. -A function or method that wants to be callable as a Task -has to return a TaskFiles object. -The input defaultdict is populated on the fly using -get_latest of the runmanager to find newest files. -Files which can not be found by get_latest must be added manually. - - - #### Atributes get_latest: diff --git a/_reference/topology.topology.qmd b/_reference/topology.topology.qmd index 29d33e32..39f34eee 100644 --- a/_reference/topology.topology.qmd +++ b/_reference/topology.topology.qmd @@ -40,7 +40,7 @@ One moleculetype in the topology ##### reindex_atomnrs { #kimmdy.topology.topology.MoleculeType.reindex_atomnrs } -`topology.topology.MoleculeType.reindex_atomnrs()` +`topology.topology.MoleculeType.reindex_atomnrs(self)` Reindex atom numbers in topology. @@ -50,7 +50,7 @@ Returns a dict, mapping of old atom number strings to new ones ##### test_for_radicals { #kimmdy.topology.topology.MoleculeType.test_for_radicals } -`topology.topology.MoleculeType.test_for_radicals()` +`topology.topology.MoleculeType.test_for_radicals(self)` Updates radical status per atom and in topology. @@ -89,7 +89,7 @@ Assumptions: ##### bind_bond { #kimmdy.topology.topology.Topology.bind_bond } -`topology.topology.Topology.bind_bond(atompair_addresses)` +`topology.topology.Topology.bind_bond(self, atompair_addresses)` Add a bond in topology. @@ -106,7 +106,7 @@ Furthermore, it modifies to function types in the topology to account for radica ##### break_bond { #kimmdy.topology.topology.Topology.break_bond } -`topology.topology.Topology.break_bond(atompair_addresses)` +`topology.topology.Topology.break_bond(self, atompair_addresses)` Break bonds in topology homolytically. @@ -122,7 +122,7 @@ Atom pairs become radicals. ##### del_atom { #kimmdy.topology.topology.Topology.del_atom } -`topology.topology.Topology.del_atom(atom_nr, parameterize=True)` +`topology.topology.Topology.del_atom(self, atom_nr, parameterize=True)` Deletes atom @@ -144,7 +144,7 @@ parameters if requested. ##### reindex_atomnrs { #kimmdy.topology.topology.Topology.reindex_atomnrs } -`topology.topology.Topology.reindex_atomnrs()` +`topology.topology.Topology.reindex_atomnrs(self)` Reindex atom numbers in topology. @@ -154,7 +154,7 @@ Returns a dict of all moleculetypes to their update maps (old -> new). ##### validate_bond { #kimmdy.topology.topology.Topology.validate_bond } -`topology.topology.Topology.validate_bond(atm1, atm2)` +`topology.topology.Topology.validate_bond(self, atm1, atm2)` Validates bond consistency between both atoms and top Returns True if bond exists, False if not. diff --git a/docs/_reference/analysis.html b/docs/_reference/analysis.html index fd0fdd74..89ebd8bc 100644 --- a/docs/_reference/analysis.html +++ b/docs/_reference/analysis.html @@ -2,7 +2,7 @@ - + @@ -49,12 +49,13 @@ "collapse-after": 3, "panel-placement": "end", "type": "overlay", - "limit": 20, + "limit": 50, "keyboard-shortcut": [ "f", "/", "s" ], + "show-item-context": false, "language": { "search-no-results-text": "No results", "search-matching-documents-text": "matching documents", @@ -90,16 +91,16 @@ @@ -162,8 +163,8 @@ -
+
+

analysis

analysis

@@ -1102,18 +1104,57 @@

Parameters

} const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -1123,27 +1164,56 @@

Parameters

instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -1221,6 +1291,32 @@

Parameters

}); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -1282,12 +1378,12 @@

Parameters

+
+

cmd

cmd

@@ -544,7 +546,7 @@

Returns

kimmdy_run

-

cmd.kimmdy_run(input=Path('kimmdy.yml'), loglevel=None, logfile=None, checkpoint='', show_plugins=False, show_schema_path=False, generate_jobscript=False, debug=False)

+

cmd.kimmdy_run(input=Path('kimmdy.yml'), loglevel=None, logfile=None, checkpoint='', show_plugins=False, show_schema_path=False, generate_jobscript=False, debug=False, callgraph=False)

Run KIMMDY from python.

Also see See get_cmdline_args or kimmdy --help for the descriptions of the arguments.

@@ -873,18 +875,57 @@

Parameters

} const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -894,27 +935,56 @@

Parameters

instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -992,6 +1062,32 @@

Parameters

}); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -1053,12 +1149,12 @@

Parameters

+
+

config

config

@@ -537,12 +539,12 @@

Methods

attr
-

config.Config.attr(attribute)

+

config.Config.attr(self, attribute)

Get the value of a specific attribute. Alias for self.__getattribute__

get_attributes
-

config.Config.get_attributes()

+

config.Config.get_attributes(self)

Get a list of all attributes without hidden ones (_<…>).

@@ -815,18 +817,57 @@
get_at } const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -836,27 +877,56 @@
get_at instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -934,6 +1004,32 @@
get_at }); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -995,12 +1091,12 @@
get_at +
+

constants

constants

@@ -733,18 +735,57 @@

Attributes

} const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -754,27 +795,56 @@

Attributes

instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -852,6 +922,32 @@

Attributes

}); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -913,12 +1009,12 @@

Attributes

+
+

coordinates

coordinates

@@ -838,18 +840,57 @@

place_atom { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -859,27 +900,56 @@

place_atom res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -957,6 +1027,32 @@

place_atom { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -1018,12 +1114,12 @@

place_atom +
+

dummyreaction.reaction.DummyReaction

reaction.DummyReaction()

@@ -708,18 +710,57 @@

dummyreaction.reaction.DummyReaction

} const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -729,27 +770,56 @@

dummyreaction.reaction.DummyReaction

instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -827,6 +897,32 @@

dummyreaction.reaction.DummyReaction

}); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -888,7 +984,7 @@

dummyreaction.reaction.DummyReaction

+
+

hat_naive.reaction.NaiveHAT

reaction.NaiveHAT()

@@ -709,18 +711,57 @@

hat_naive.reaction.NaiveHAT

} const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -730,27 +771,56 @@

hat_naive.reaction.NaiveHAT

instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -828,6 +898,32 @@

hat_naive.reaction.NaiveHAT

}); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -889,12 +985,12 @@

hat_naive.reaction.NaiveHAT

+
+

homolysis.reaction.Homolysis

reaction.Homolysis()

@@ -709,18 +711,57 @@

homolysis.reaction.Homolysis

} const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -730,27 +771,56 @@

homolysis.reaction.Homolysis

instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -828,6 +898,32 @@

homolysis.reaction.Homolysis

}); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -889,12 +985,12 @@

homolysis.reaction.Homolysis

+
+

Reference

@@ -837,18 +839,57 @@

Reaction Plugins

} const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -858,27 +899,56 @@

Reaction Plugins

instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -956,6 +1026,32 @@

Reaction Plugins

}); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -1017,12 +1113,12 @@

Reaction Plugins

+
+

kmc

kmc

@@ -1010,18 +1012,57 @@

Parameters

} const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -1031,27 +1072,56 @@

Parameters

instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -1129,6 +1199,32 @@

Parameters

}); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -1190,12 +1286,12 @@

Parameters

+
+

parsing.TopologyDict

parsing.TopologyDict

@@ -709,18 +711,57 @@

parsing.TopologyDict

} const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -730,27 +771,56 @@

parsing.TopologyDict

instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -828,6 +898,32 @@

parsing.TopologyDict

}); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -889,12 +985,12 @@

parsing.TopologyDict

+
+

parsing

parsing

@@ -868,7 +870,6 @@

Examples

resolve_includes

parsing.resolve_includes(path, gmx_builtin_ffs=None)

-

Resolve #include statements in a (top/itp) file.

Arguments

path : Filepath to read.

@@ -1232,18 +1233,57 @@

Parameters

} const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -1253,27 +1293,56 @@

Parameters

instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -1351,6 +1420,32 @@

Parameters

}); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -1412,12 +1507,12 @@

Parameters

+
+

plugins

plugins

@@ -505,7 +507,7 @@

Methods

parameterize_topology
-

plugins.BasicParameterizer.parameterize_topology(current_topology)

+

plugins.BasicParameterizer.parameterize_topology(self, current_topology)

Do nothing, all necessary actions should already have happened in bind_bond and break_bond of Topology

@@ -559,7 +561,7 @@

Methods

get_recipe_collection
-

plugins.ReactionPlugin.get_recipe_collection(files)

+

plugins.ReactionPlugin.get_recipe_collection(self, files)

Get a RecipeCollection as a result of the reaction.

This is run as a Task in the RunManager. How the RecipeCollection is built is up to the reaction. It has access to the current state of the system via the runmanager self.runmng and the files.

@@ -854,18 +856,57 @@
Parameters
} const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -875,27 +916,56 @@
Parameters
instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -973,6 +1043,32 @@
Parameters
}); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -1034,12 +1130,12 @@
Parameters
+
+

recipe

recipe

@@ -789,7 +791,7 @@

Methods

calc_averages
-

recipe.Recipe.calc_averages(window_size)

+

recipe.Recipe.calc_averages(self, window_size)

Calulate average rates over some window size

Parameters
@@ -815,12 +817,12 @@
Parameters
check_consistency
-

recipe.Recipe.check_consistency()

+

recipe.Recipe.check_consistency(self)

Run consistency checks for correct size of variables

combine_with
-

recipe.Recipe.combine_with(other)

+

recipe.Recipe.combine_with(self, other)

Combines this Recipe with another with the same RecipeSteps.

Parameters
@@ -909,17 +911,17 @@

Methods

aggregate_reactions
-

recipe.RecipeCollection.aggregate_reactions()

+

recipe.RecipeCollection.aggregate_reactions(self)

Combines reactions having the same sequence of RecipeSteps.

calc_cumprob
-

recipe.RecipeCollection.calc_cumprob()

+

recipe.RecipeCollection.calc_cumprob(self)

Calculate cumulative probability of all contained recipe steps. Sums up to 1 over all recipes. Assumes constant rate for given timespan and rate zero otherwise.

calc_ratesum
-

recipe.RecipeCollection.calc_ratesum()

+

recipe.RecipeCollection.calc_ratesum(self)

Calculate the sum of rates over all timesteps

Returns
@@ -953,12 +955,12 @@
Returns
from_csv
-

recipe.RecipeCollection.from_csv(path)

+

recipe.RecipeCollection.from_csv(cls, path)

Create a RecipeCollection object from a CSV file Returns the recipe collection and a single recipe that was picked, otherwise None

plot
-

recipe.RecipeCollection.plot(outfile, highlight_r=None, highlight_t=None)

+

recipe.RecipeCollection.plot(self, outfile, highlight_r=None, highlight_t=None)

Plot reaction rates over time

Parameters
@@ -996,7 +998,7 @@
Parameters
to_csv
-

recipe.RecipeCollection.to_csv(path, picked_recipe=None)

+

recipe.RecipeCollection.to_csv(self, path, picked_recipe=None)

Write a ReactionResult as defined in the reaction module to a csv file

@@ -1280,18 +1282,57 @@

Relax

} const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -1301,27 +1342,56 @@

Relax

instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -1399,6 +1469,32 @@

Relax

}); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -1460,12 +1556,12 @@

Relax

+
+

runmanager

runmanager

@@ -593,13 +595,13 @@

Methods

get_latest
-

runmanager.RunManager.get_latest(suffix)

+

runmanager.RunManager.get_latest(self, suffix)

Returns path to latest file of given type.

For .dat files (in general ambiguous extensions) use full file name. Errors if file is not found.

write_one_checkpoint
-

runmanager.RunManager.write_one_checkpoint()

+

runmanager.RunManager.write_one_checkpoint(self)

Just write the first checkpoint and then exit

Used to generate a starting point for jobscripts on hpc clusters that can easily self-submit after a timelimit was exceeded.

@@ -900,18 +902,57 @@

get_e } const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -921,27 +962,56 @@

get_e instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -1019,6 +1089,32 @@

get_e }); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -1080,12 +1176,12 @@

get_e +
+

schema

schema

@@ -893,18 +895,57 @@

prune

} const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -914,27 +955,56 @@

prune

instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -1012,6 +1082,32 @@

prune

}); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { diff --git a/docs/_reference/tasks.html b/docs/_reference/tasks.html index e756c19c..be5f45a3 100644 --- a/docs/_reference/tasks.html +++ b/docs/_reference/tasks.html @@ -2,7 +2,7 @@ - + @@ -22,7 +22,7 @@ } /* CSS for syntax highlighting */ pre > code.sourceCode { white-space: pre; position: relative; } -pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } +pre > code.sourceCode > span { line-height: 1.25; } pre > code.sourceCode > span:empty { height: 1.2em; } .sourceCode { overflow: visible; } code.sourceCode > span { color: inherit; text-decoration: inherit; } @@ -83,12 +83,13 @@ "collapse-after": 3, "panel-placement": "end", "type": "overlay", - "limit": 20, + "limit": 50, "keyboard-shortcut": [ "f", "/", "s" ], + "show-item-context": false, "language": { "search-no-results-text": "No results", "search-matching-documents-text": "matching documents", @@ -124,16 +125,16 @@ @@ -196,8 +197,8 @@ - +
+

tasks

tasks

@@ -527,8 +529,6 @@

AutoFillDict

Task

tasks.Task(self, runmng, f, kwargs=None, out=None)

-

A task to be performed as as a step in the RunManager.

-

A task consists of a function and its keyword arguments. Calling a taks calls the stored function. The function must return a TaskFiles object.

Parameters:

runmng Runmanager instance from which the task is called f Function that will be called when the task is called kwargs kwargs to be passed to f out If not None, an output dir will be created with this name

@@ -537,8 +537,6 @@

Parameters:

TaskFiles

tasks.TaskFiles(get_latest, input=field(default_factory=dict), output=field(default_factory=dict), outputdir=Path(), logger=logging.getLogger('kimmdy.basetask'))

-

Class for Task input and output files and directories.

-

Hosts the input and output file paths belonging to a task. A function or method that wants to be callable as a Task has to return a TaskFiles object. The input defaultdict is populated on the fly using get_latest of the runmanager to find newest files. Files which can not be found by get_latest must be added manually.

Atributes

get_latest: Runmanager.get_latest function that returns paths to the latest file of given type. input: Input file paths for a Task. Is populated by get_latest or manually. output: Output file paths for a Task. Is populated by runmanager._discover_output_files or manually. outputdir: Output directory for a Task. Typically populated by create_task_directory called by Task. logger: Logger for a Task. Initialized in create_task_directory.

@@ -846,18 +844,57 @@

create_ } const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -867,27 +904,56 @@

create_ instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -965,6 +1031,32 @@

create_ }); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -1026,12 +1118,12 @@

create_ +
+

tools

tools

@@ -921,18 +923,57 @@

write_top_as } const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -942,27 +983,56 @@

write_top_as instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -1040,6 +1110,32 @@

write_top_as }); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -1101,12 +1197,12 @@

write_top_as +
+

topology.atomic

topology.atomic

@@ -935,18 +937,57 @@

Residue } const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -956,27 +997,56 @@

Residue instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -1054,6 +1124,32 @@

Residue }); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -1115,12 +1211,12 @@

Residue +
+

topology.ff

topology.ff

@@ -736,18 +738,57 @@

FF

} const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -757,27 +798,56 @@

FF

instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -855,6 +925,32 @@

FF

}); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -916,12 +1012,12 @@

FF

+
+

topology.topology

topology.topology

@@ -572,13 +574,13 @@

Methods

reindex_atomnrs
-

topology.topology.MoleculeType.reindex_atomnrs()

+

topology.topology.MoleculeType.reindex_atomnrs(self)

Reindex atom numbers in topology.

Starts at index 1. This also updates the numbers for bonds, angles, dihedrals and pairs. Returns a dict, mapping of old atom number strings to new ones

test_for_radicals
-

topology.topology.MoleculeType.test_for_radicals()

+

topology.topology.MoleculeType.test_for_radicals(self)

Updates radical status per atom and in topology.

Iterate over all atoms and designate them as radicals if they have fewer bounds than their natural bond order.

@@ -648,7 +650,7 @@

Methods

bind_bond
-

topology.topology.Topology.bind_bond(atompair_addresses)

+

topology.topology.Topology.bind_bond(self, atompair_addresses)

Add a bond in topology.

Modifies the topology dictionary in place. It keeps track of affected terms in the topology via a graph representation of the topology and applies the necessary changes to bonds, angles and dihedrals (proper and improper). Furthermore, it modifies to function types in the topology to account for radicals.

@@ -675,7 +677,7 @@
Parameters
break_bond
-

topology.topology.Topology.break_bond(atompair_addresses)

+

topology.topology.Topology.break_bond(self, atompair_addresses)

Break bonds in topology homolytically.

Removes bond, angles and dihedrals where atompair was involved. Modifies the topology dictionary in place. Atom pairs become radicals.

@@ -702,7 +704,7 @@
Parameters
del_atom
-

topology.topology.Topology.del_atom(atom_nr, parameterize=True)

+

topology.topology.Topology.del_atom(self, atom_nr, parameterize=True)

Deletes atom

Deletes atom and all attached bonds. Reindexes the top and updates the parameters if requested.

@@ -756,13 +758,13 @@
Returns
reindex_atomnrs
-

topology.topology.Topology.reindex_atomnrs()

+

topology.topology.Topology.reindex_atomnrs(self)

Reindex atom numbers in topology.

Starts at index 1. This also updates the numbers for bonds, angles, dihedrals and pairs. Returns a dict of all moleculetypes to their update maps (old -> new).

validate_bond
-

topology.topology.Topology.validate_bond(atm1, atm2)

+

topology.topology.Topology.validate_bond(self, atm1, atm2)

Validates bond consistency between both atoms and top Returns True if bond exists, False if not. Raises RuntimeError if bond is not consistent.

@@ -1035,18 +1037,57 @@
{ + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -1056,27 +1097,56 @@
res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -1154,6 +1224,32 @@
{ + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -1215,12 +1311,12 @@
diff --git a/docs/_reference/topology.utils.html b/docs/_reference/topology.utils.html index e2b891a1..c44378e4 100644 --- a/docs/_reference/topology.utils.html +++ b/docs/_reference/topology.utils.html @@ -2,7 +2,7 @@ - + @@ -49,12 +49,13 @@ "collapse-after": 3, "panel-placement": "end", "type": "overlay", - "limit": 20, + "limit": 50, "keyboard-shortcut": [ "f", "/", "s" ], + "show-item-context": false, "language": { "search-no-results-text": "No results", "search-matching-documents-text": "matching documents", @@ -90,16 +91,16 @@ @@ -162,8 +163,8 @@ - +
+

topology.utils

topology.utils

@@ -801,18 +803,57 @@

set_ } const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -822,27 +863,56 @@

set_ instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -920,6 +990,32 @@

set_ }); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -981,12 +1077,12 @@

set_ +
+

utils

utils

@@ -1034,18 +1036,57 @@

Parameters

} const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -1055,27 +1096,56 @@

Parameters

instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -1153,6 +1223,32 @@

Parameters

}); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -1214,12 +1310,12 @@

Parameters

+
+

Contribute

KIMMDY uses conventional commits and semantic versioning, automated via release please.

@@ -772,18 +774,57 @@

Local testing

} const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -793,27 +834,56 @@

Local testing

instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -891,6 +961,32 @@

Local testing

}); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -952,12 +1048,12 @@

Local testing

+
@@ -486,8 +487,10 @@

High Performance Computing

+ +

Setup

You need an installation of python (>= 3.10) and (possibly PLUMED patched) GROMACS in your HPC environment.

@@ -769,18 +772,57 @@

Setup

} const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -790,27 +832,56 @@

Setup

instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -888,6 +959,32 @@

Setup

}); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -949,12 +1046,12 @@

Setup

@@ -491,8 +492,10 @@

KIMMDY Options

+ +

Autocompletion

KIMMDY comes with autocompletion for the kimmdy.yml file. You can add the schema to the configuration of the yaml-language-server in your editor (e.g. VS Code via the YAML extension or Neovim via lspconfig). To associate kimmdy.yml files with KIMMDY, add the following to your

@@ -502,7 +505,7 @@

VS Code settings

settings.json
-
"yaml.schemas": {
+
"yaml.schemas": {
     "https://raw.githubusercontent.com/hits-mbm-dev/kimmdy/main/src/kimmdy/kimmdy-yaml-schema.json": "kimmdy.yml",
 }
@@ -513,7 +516,7 @@

Neovim settings

init.lua
-
require("lspconfig").yamlls.setup({
+
require("lspconfig").yamlls.setup({
   on_attach = on_attach,
   capabilities = capabilities,
   flags = lsp_flags,
@@ -531,9 +534,13 @@ 

Neovim settings

All Options

The following is a list of the options that can be set in the kimmdy.yml file. It includes reactions currently available in KIMMDY as plugins. Nested options are separated by a .. * denotes an arbitrary name for a section. The key for a section is bold.

-
+
+
+
+Table 1: KIMMDY options +
+
-@@ -559,68 +566,68 @@

All Options

+ + + + + + + - + - + - + - + - + - + - + - + - - - - - - - @@ -637,14 +644,14 @@

All Options

- + - + @@ -672,14 +679,14 @@

All Options

- + - + @@ -714,14 +721,14 @@

All Options

- + - + @@ -749,14 +756,14 @@

All Options

- + - + @@ -764,6 +771,8 @@

All Options

Table 1: KIMMDY options
write_checkpointWrite checkpoints to continue a KIMMDY run from. Default TrueboolTrue
cwdWorking directoryWorking directory. Default is current working directory Path
name Used for output folder if out is not specified str kimmdy
out Output folder Path
log Settings for logging
max_tasks Maximum number of tasks to run. This is useful when a task in the sequence can dymanically add more tasks. 0 means no limit. int 0
max_hours Stop KIMMDY after max_hours hours. Set this lower than the limit of your HPC cluster for use with a re-submit jobscript. 0 Means no limit. int 0
kmc KMC algorithm overwrite. Should be set by the reactions, but can be changed here. str
tau_scale Scaling parameter for tau in the extrande kmc algorithm. float 1.0
runReplica numberint1
top Topology file
ndxIndex fileGromaxs index file Path index.ndx
gromacs_aliasGromacs aliasGromacs alias. e.g. gmx or mpirun gmx_mpi str gmx
tpr.tpr file of a finished simulation for starting with reaction.tpr file of a finished simulation for starting directly with a reaction Path
trr.trr file of a finished simulation for starting with reaction.trr file of a finished simulation for starting directly with a reaction Path
changer.coordinates.mdWhich MD instance from the ‘mds’ section is used for relaxation MDsMD step from the ‘mds’ section that is used for relaxation MDs str
changer.coordinates.slow_growthWhether the chosen MD instance is a slow growth/free-energy simulationWhether the chosen MD step is a slow growth/free-energy simulation bool False
plot_ratesPlot the reaction ratesPlot the reaction rates during the reactions step bool True
save_recipesSave recipes as csv during decide_reactionSave recipes as csv during the reactions step bool True
+
+

Example kimmdy.yml Files

@@ -771,7 +780,7 @@

Example kim
kimmdy.yml
-
dryrun: false
+
dryrun: false
 max_tasks: 100
 name: 'hat_tf_000'
 gromacs_alias: 'gmx'
@@ -1066,18 +1075,57 @@ 

Example kim } const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -1087,27 +1135,56 @@

Example kim instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -1185,6 +1262,32 @@

Example kim }); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -1246,12 +1349,12 @@

Example kim

-
+

Write Reaction Plugins

TODO

@@ -708,18 +710,57 @@

Write Reaction Plugins

} const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -729,27 +770,56 @@

Write Reaction Plugins

instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -827,6 +897,32 @@

Write Reaction Plugins

}); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -888,12 +984,12 @@

Write Reaction Plugins

-
@@ -485,17 +486,19 @@

Visualize Topologies

+ +

Hexala

-
+
from kimmdy.parsing import read_top
 from kimmdy.topology.topology import Topology
 from pathlib import Path
 from kimmdy.tools import write_top_as_dot
-
+
ala_top = read_top(Path('../../tests/test_files/test_topology/urea.top'), use_gmx_dir=False)
 top = Topology(ala_top)
 
@@ -504,77 +507,103 @@ 

Hexala

-
+
+
- -G - - - -1 C - - 1 C - -2 O - - 2 O - -1 C–2 O - - - -3 N - - 3 N - -1 C–3 N - - - -6 N - - 6 N - -1 C–6 N - - - -4 H - - 4 H - -3 N–4 H - - - -5 H - - 5 H - -3 N–5 H - - - -7 H - - 7 H - -6 N–7 H - - - -8 H - - 8 H - -6 N–8 H - - +G + + + +1 C + +1 C + + + +2 O + +2 O + + + +1 C--2 O + + + + +3 N + +3 N + + + +1 C--3 N + + + + +6 N + +6 N + + + +1 C--6 N + + + + +4 H + +4 H + + + +3 N--4 H + + + + +5 H + +5 H + + + +3 N--5 H + + + + +7 H + +7 H + + + +6 N--7 H + + + + +8 H + +8 H + + + +6 N--8 H + + +
-
Figure 1: A diagram of the ala topology
+
+
+Figure 1: A diagram of the ala topology +
@@ -846,18 +875,57 @@

Hexala

} const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -867,27 +935,56 @@

Hexala

instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -965,6 +1062,32 @@

Hexala

}); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -1026,13 +1149,13 @@

Hexala

diff --git a/docs/guide/index.html b/docs/guide/index.html index afe11f37..5084d49f 100644 --- a/docs/guide/index.html +++ b/docs/guide/index.html @@ -2,7 +2,7 @@ - + @@ -48,12 +48,13 @@ "collapse-after": 3, "panel-placement": "end", "type": "overlay", - "limit": 20, + "limit": 50, "keyboard-shortcut": [ "f", "/", "s" ], + "show-item-context": false, "language": { "search-no-results-text": "No results", "search-matching-documents-text": "matching documents", @@ -89,16 +90,16 @@ @@ -161,8 +162,8 @@
- - +
+

1. Run KIMMDY from Colbuilder fibril

@@ -567,7 +569,7 @@

Simulation

kimmdy.yml
-
# yaml-language-server: $schema=../../src/kimmdy/kimmdy-yaml-schema.json
+
# yaml-language-server: $schema=../../src/kimmdy/kimmdy-yaml-schema.json
 dryrun: false
 name: 'hexalanine_homolysis_000'
 max_tasks: 100
@@ -620,7 +622,7 @@ 

Simulation

kimmdy.yml
-
# yaml-language-server: $schema=../../src/kimmdy/kimmdy-yaml-schema.json
+
# yaml-language-server: $schema=../../src/kimmdy/kimmdy-yaml-schema.json
 
 dryrun: false
 name: 'fibril_000'
@@ -930,18 +932,57 @@ 

Analysis

} const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -951,27 +992,56 @@

Analysis

instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -1049,6 +1119,32 @@

Analysis

}); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -1110,12 +1206,12 @@

Analysis

- - +
+

0. Getting Started

Let’s jump right in!

@@ -522,7 +524,7 @@

Setup the Simulation<
kimmdy.yml
-
dryrun: false
+
dryrun: false
 max_tasks: 100
 name: 'hat_tf_000'
 gromacs_alias: 'gmx'
@@ -566,7 +568,7 @@ 

Setup the Simulation<

Our starting structure is a simple ACE/NME-capped Alanine molecule in a box of water.

@@ -863,18 +865,57 @@

Analyse the Simulat } const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -884,27 +925,56 @@

Analyse the Simulat instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -982,6 +1052,32 @@

Analyse the Simulat }); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -1043,12 +1139,12 @@

Analyse the Simulat

-
+ +

Tutorials to help you get familiar with KIMMDY.

@@ -714,18 +717,57 @@

Tutorials

} const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -735,27 +777,56 @@

Tutorials

instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; - try { hash = new URL(url).hash; } catch {} - const id = hash.replace(/^#\/?/, ""); - const note = window.document.getElementById(id); - if (note !== null) { - try { - const html = processXRef(id, note); - instance.setContent(html); - } finally { - instance.enable(); - instance.show(); + if (url.startsWith('#')) { + hash = url; + } else { + try { hash = new URL(url).hash; } catch {} + } + if (hash) { + const id = hash.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + if (note !== null) { + try { + const html = processXRef(id, note.cloneNode(true)); + instance.setContent(html); + } finally { + instance.enable(); + instance.show(); + } + } else { + // See if we can fetch this + fetch(url.split('#')[0]) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -833,6 +904,32 @@

Tutorials

}); selectedAnnoteEl = undefined; }; + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -894,12 +991,12 @@

Tutorials

-
@@ -492,8 +493,10 @@

2. Writing a Reaction Plugin

+ +

In this tutorial, you will learn how to create your own reaction plugin in a GitHub repository.

Creating a GitHub repository

@@ -505,7 +508,7 @@

Add

Main code

A reaction plugin has to be a derived class from the ReactionPlugin base class. Such a class has the attributes name, runmng and config and the method get_recipe_collection, which takes a TaskFiles object as argument and returns a RecipeCollection.

The name is a simple string and may be useful for logging. runmng is the central RunManager of a kimmdy run and has plenty of useful attributes for your plugin, especially the system Topology, which can be accessed via self.runmg.top. config contains the reaction plugin configuration as specified in the kimmdy configuration file (typically named kimmdy.yml). A RecipeCollection contains Recipes with predefined RecipeSteps that can be used to define the modification to the system for the reaction. A Recipe also contains the rates of the specified reaction and the timespans during which the corresponding rates are valid. An example plugin can be seen below.

-
+
Plugin main code (reaction.py)
from kimmdy.recipe import (
@@ -565,7 +568,7 @@ 

Main code

Configuration file schema

A plugin defines which variables it needs in a schema. The schema can contain default values and types of these variables. For a Kimmdy run, reaction plugin variables are defined in the configuration file (kimmdy.yml). An example schema can be seen below.

-
+
Plugin schema (kimmdy-yaml-schema.json)
{
@@ -597,7 +600,7 @@ 

Configuration fi

Making a python package

It is necessary to make the plugin a python package to interface with Kimmdy. For this, package setup configuration files are necessary, for example setup.py and setup.cfg. In setup.cfg dependencies can be specified, which will be installed alongside the plugin. The interface with kimmdy is specified in the [options.entry_points] section. This section needs to refer to the class we created in the plugin main code and assign it to kimmdy.reaction_plugins, i.e. kimmdy.reaction_plugins = bind = <path>.<to>.<main file>:<ClassName>. Also, the directory containing the source code (typically src) is defined in [options.packages.find]. An example for setup.py and setup.cfg can be found below.

-
+
setup.py
from setuptools import setup
@@ -605,7 +608,7 @@ 

Making a python pa setup()

-
+
setup.cfg
[metadata]
@@ -911,18 +914,57 @@ 

{ - if (id.startsWith('sec-')) { + // Strip column container classes + const stripColumnClz = (el) => { + el.classList.remove("page-full", "page-columns"); + if (el.children) { + for (const child of el.children) { + stripColumnClz(child); + } + } + } + stripColumnClz(note) + const typesetMath = (el) => { + if (window.MathJax) { + // MathJax Typeset + window.MathJax.typeset([el]); + } else if (window.katex) { + // KaTeX Render + var mathElements = el.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + window.katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains('display'), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } + } + } + if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { for (let i = 0; i < 2; i++) { container.appendChild(note.children[i].cloneNode(true)); } + typesetMath(container); return container.innerHTML } else { + typesetMath(note); return note.innerHTML; } } else { + // Remove any anchor links if they are present + const anchorLink = note.querySelector('a.anchorjs-link'); + if (anchorLink) { + anchorLink.remove(); + } + typesetMath(note); return note.innerHTML; } } @@ -932,27 +974,56 @@

res.text()) + .then(html => { + const parser = new DOMParser(); + const htmlDoc = parser.parseFromString(html, "text/html"); + const note = htmlDoc.getElementById(id); + if (note !== null) { + const html = processXRef(id, note); + instance.setContent(html); + } + }).finally(() => { + instance.enable(); + instance.show(); + }); } } else { - // See if we can fetch this - fetch(url.split('#')[0]) + // See if we can fetch a full url (with no hash to target) + // This is a special case and we should probably do some content thinning / targeting + fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); - const note = htmlDoc.getElementById(id); + const note = htmlDoc.querySelector('main.content'); if (note !== null) { - const html = processXRef(id, note); + // This should only happen for chapter cross references + // (since there is no id in the URL) + // remove the first header + if (note.children.length > 0 && note.children[0].tagName === "HEADER") { + note.children[0].remove(); + } + const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { @@ -1030,6 +1101,32 @@

{ + elRect = undefined; + if (selectedAnnoteEl) { + selectCodeLines(selectedAnnoteEl); + } + }, 10) + ); + function throttle(fn, ms) { + let throttle = false; + let timer; + return (...args) => { + if(!throttle) { // first call gets through + fn.apply(this, args); + throttle = true; + } else { // all the others get throttled + if(timer) clearTimeout(timer); // cancel #2 + timer = setTimeout(() => { + fn.apply(this, args); + timer = throttle = false; + }, ms); + } + }; + } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { @@ -1091,13 +1188,13 @@

diff --git a/docs/index.html b/docs/index.html index 280c5012..8edcc05e 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2,7 +2,7 @@ - + @@ -47,12 +47,13 @@ "collapse-after": 3, "panel-placement": "end", "type": "overlay", - "limit": 20, + "limit": 50, "keyboard-shortcut": [ "f", "/", "s" ], + "show-item-context": false, "language": { "search-no-results-text": "No results", "search-matching-documents-text": "matching documents", @@ -88,16 +89,16 @@ @@ -160,8 +161,8 @@