import mmf_setup
mmf_setup.nbinit()

This cell adds /home/docs/checkouts/readthedocs.org/user_builds/gpe/checkouts/latest/src to your path, and contains some definitions for equations and some CSS for styling the notebook. If things look a bit strange, please try the following:

  • Choose "Trust Notebook" from the "File" menu.
  • Re-execute this cell.
  • Reload the notebook.

Programming Interfaces#

To make programming easier and ensure that future versions of the code work well, we defined some programming interfaces to glue various pieces together. This system consists of several interrelated parts.

States#

At the lowest level are the various IState interfaces defined in the pytimeode project. Objects that implement these interfaces can be used with the various evolvers provided by the pytimeode class. At a minimum, the user must define the IStateMinimal interface (though much of this is provided by various mixin classes) and one of the following:

  • IStateForABMEvolvers: This essentially requires that the user provide a compute_dy_dt(dy) method which computes the time-derivative of the state and stores it in dy. This allows one to use the pytimeode.evolvers.EvolverABM evolver for high-precision time-evolution. If the basis resolution is chosen correctly, one should be able to evolve with a timestep of up to dt=0.5*state.t_scale with values of 0.2 being quite typical. (If dt must be significantly smaller, you probably do not have sufficient resolution in your state.) One advantage of this evolver is that, if it converges, it is generally accurate. Once convergence is broken, the evolver usually blows up, raising floating-point errors (NaNs, Inf, etc.).

  • IStateForSplitEvolvers: This essentially requires that the user provide two methods: apply_exp_K(dt) and apply_exp_V(dt, state) which apply the exponential of the kinetic and potential operators over time interval dt to the state. This requires the true matrix exponential of these operators, so (modulo clever reasoning) requires that these operators be diagonalizable in either the position (for \(\op{V}\)) or momentum (for \(\op{K}\)) bases. If these can be implement, this gives a low-order, but unitary evolution scheme that can be used with large time-steps to get a qualitative (but usually not quantitative) idea of what is happening. Large time-steps can be used here with imaginary time cooling to good effect. This can also be invaluable when designing a problem and for debugging.

Here we define a variety of states that implement various physical scenarios. For example, we have different states for different bases – periodic, axial, tubes, etc. – and for different types of problems such as single-component or multi-component mixtures.

To complement these, we provide a set of experiment classes which are intended to define an experimental protocol that can be used

Experiment#

Reference#

Here are the programmatically generated interfaces:

IStateForABMEvolvers#

from mmfutils.interface import describe_interface
from pytimeode import interfaces
[I 03:37:50 root] Patching zope.interface.document.asReStructuredText to format code
[I 03:37:51 numexpr.utils] NumExpr defaulting to 2 threads.
display(describe_interface(interfaces.IStateForABMEvolvers))
<string>

IStateForABMEvolvers

Interface required by ABM and similar integration based evolvers.

These evolvers are very general, requiring only the ability for the problem to compute $dy/dt$.

This interface extends:

o IState

Attributes:

Methods:

compute_dy_dt(dy) -- Return dy/dt at time self.t using the memory in state dy.

Warning: dy is simply recycled memory that should be used if possible. It contains no useful information. (I.e., compute dy/dt for the current state y == self.

IStateForSplitEvolvers#

display(describe_interface(interfaces.IStateForSplitEvolvers))
<string>

IStateForSplitEvolvers

Interface required by Split Operator evolvers.

These evolvers assume the problem can be split into two operators - $K$ (kinetic energy) and $V$ (potential energy) so that $i dy/dt = (K+V)y$. The method requires that each of these operators be exponentiated. The approach uses a Trotter decomposition that provides higher order accuracy, but requires evaluation of the potentials at an intermediate time.

This interface requires that the apply_exp_V() method accept another state object which should be used for calculating any non-linear terms in $V$ which are state dependent.

If your problem is linear (i.e. $V$ depends only on time, not on the state as in the case of the usual linear Schrodinger equation), then you should set the linear attribute which will improve performance (but do not use this for non-linear problems or the order of convergence will be reduced).

This interface extends:

o IState

Attributes:

linear -- Is the problem linear?

Methods:

apply_exp_K(dt) -- Apply $e^{-i K dt}$ in place

apply_exp_V(dt, state) -- Apply $e^{-i V dt}$ in place using state for any nonlinear dependence in V. (Linear problems should ignore state.)

IStateMinimal#

display(describe_interface(interfaces.IStateMinimal))
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[6], line 1
----> 1 display(describe_interface(interfaces.IStateMinimal))

AttributeError: module 'pytimeode.interfaces' has no attribute 'IStateMinimal'

IState#

display(describe_interface(interfaces.IState))
<string>:71: (SEVERE/4) Unexpected section title.

Arguments
---------
---------------------------------------------------------------------------
SystemMessage                             Traceback (most recent call last)
Cell In[7], line 1
----> 1 display(describe_interface(interfaces.IState))

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/mmfutils/interface.py:207, in describe_interface(interface, format)
    204 if format.lower() == "rst":
    205     return rst
--> 207 html = core.publish_string(rst, writer=writer).decode()
    208 if format.lower() == "html":
    209     return html

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/core.py:460, in publish_string(source, source_path, destination_path, reader, reader_name, parser, parser_name, writer, writer_name, settings, settings_spec, settings_overrides, config_section, enable_exit_status)
    436 def publish_string(source, source_path=None, destination_path=None,
    437                    reader=None, reader_name='standalone',
    438                    parser=None, parser_name='restructuredtext',
   (...)    441                    settings_overrides=None, config_section=None,
    442                    enable_exit_status=False):
    443     """
    444     Set up & run a `Publisher` for programmatic use with string I/O.
    445 
   (...)    458         https://docutils.sourceforge.io/docs/user/config.html#output-encoding
    459     """
--> 460     output, publisher = publish_programmatically(
    461         source_class=io.StringInput, source=source, source_path=source_path,
    462         destination_class=io.StringOutput,
    463         destination=None, destination_path=destination_path,
    464         reader=reader, reader_name=reader_name,
    465         parser=parser, parser_name=parser_name,
    466         writer=writer, writer_name=writer_name,
    467         settings=settings, settings_spec=settings_spec,
    468         settings_overrides=settings_overrides,
    469         config_section=config_section,
    470         enable_exit_status=enable_exit_status)
    471     return output

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/core.py:722, in publish_programmatically(source_class, source, source_path, destination_class, destination, destination_path, reader, reader_name, parser, parser_name, writer, writer_name, settings, settings_spec, settings_overrides, config_section, enable_exit_status)
    720 publisher.set_source(source, source_path)
    721 publisher.set_destination(destination, destination_path)
--> 722 output = publisher.publish(enable_exit_status=enable_exit_status)
    723 return output, publisher

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/core.py:234, in Publisher.publish(self, argv, usage, description, settings_spec, settings_overrides, config_section, enable_exit_status)
    232 self.set_io()
    233 self.prompt()
--> 234 self.document = self.reader.read(self.source, self.parser,
    235                                  self.settings)
    236 self.apply_transforms()
    237 output = self.writer.write(self.document, self.destination)

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/readers/__init__.py:70, in Reader.read(self, source, parser, settings)
     68 self.settings = settings
     69 self.input = self.source.read()
---> 70 self.parse()
     71 return self.document

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/readers/__init__.py:76, in Reader.parse(self)
     74 """Parse `self.input` into a document tree."""
     75 self.document = document = self.new_document()
---> 76 self.parser.parse(self.input, document)
     77 document.current_source = document.current_line = None

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/parsers/rst/__init__.py:184, in Parser.parse(self, inputstring, document)
    182         break
    183 else:
--> 184     self.statemachine.run(inputlines, document, inliner=self.inliner)
    185 # restore the "default" default role after parsing a document
    186 if '' in roles._roles:

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/parsers/rst/states.py:169, in RSTStateMachine.run(self, input_lines, document, input_offset, match_titles, inliner)
    167 self.reporter = self.memo.reporter
    168 self.node = document
--> 169 results = StateMachineWS.run(self, input_lines, input_offset,
    170                              input_source=document['source'])
    171 assert results == [], 'RSTStateMachine.run() results should be empty!'
    172 self.node = self.memo = None

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/statemachine.py:233, in StateMachine.run(self, input_lines, input_offset, context, input_source, initial_state)
    228         source, offset = self.input_lines.info(
    229             self.line_offset)
    230         print(f'\nStateMachine.run: line '
    231               f'(source={source!r}, offset={offset!r}):\n'
    232               f'| {self.line}', file=sys.stderr)
--> 233     context, next_state, result = self.check_line(
    234         context, state, transitions)
    235 except EOFError:
    236     if self.debug:

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/statemachine.py:445, in StateMachine.check_line(self, context, state, transitions)
    441         if self.debug:
    442             print('\nStateMachine.check_line: Matched transition '
    443                   f'"{name}" in state "{state.__class__.__name__}".',
    444                   file=sys.stderr)
--> 445         return method(match, context, next_state)
    446 else:
    447     if self.debug:

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/parsers/rst/states.py:1170, in Body.indent(self, match, context, next_state)
   1167 """Block quote."""
   1168 (indented, indent, line_offset, blank_finish
   1169  ) = self.state_machine.get_indented()
-> 1170 elements = self.block_quote(indented, line_offset)
   1171 self.parent += elements
   1172 if not blank_finish:

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/parsers/rst/states.py:1187, in Body.block_quote(self, indented, line_offset)
   1180 (blockquote.source, blockquote.line
   1181  ) = self.state_machine.get_source_and_line(line_offset+1)
   1182 (blockquote_lines,
   1183  attribution_lines,
   1184  attribution_offset,
   1185  indented,
   1186  new_line_offset) = self.split_attribution(indented, line_offset)
-> 1187 self.nested_parse(blockquote_lines, line_offset, blockquote)
   1188 elements.append(blockquote)
   1189 if attribution_lines:

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/parsers/rst/states.py:279, in RSTState.nested_parse(self, block, input_offset, node, match_titles, state_machine_class, state_machine_kwargs)
    276 if not state_machine:
    277     state_machine = state_machine_class(debug=self.debug,
    278                                         **state_machine_kwargs)
--> 279 state_machine.run(block, input_offset, memo=self.memo,
    280                   node=node, match_titles=match_titles)
    281 if use_default == 2:
    282     self.nested_sm_cache.append(state_machine)

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/parsers/rst/states.py:195, in NestedStateMachine.run(self, input_lines, input_offset, memo, node, match_titles)
    193 self.language = memo.language
    194 self.node = node
--> 195 results = StateMachineWS.run(self, input_lines, input_offset)
    196 assert results == [], ('NestedStateMachine.run() results should be '
    197                        'empty!')
    198 return results

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/statemachine.py:233, in StateMachine.run(self, input_lines, input_offset, context, input_source, initial_state)
    228         source, offset = self.input_lines.info(
    229             self.line_offset)
    230         print(f'\nStateMachine.run: line '
    231               f'(source={source!r}, offset={offset!r}):\n'
    232               f'| {self.line}', file=sys.stderr)
--> 233     context, next_state, result = self.check_line(
    234         context, state, transitions)
    235 except EOFError:
    236     if self.debug:

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/statemachine.py:445, in StateMachine.check_line(self, context, state, transitions)
    441         if self.debug:
    442             print('\nStateMachine.check_line: Matched transition '
    443                   f'"{name}" in state "{state.__class__.__name__}".',
    444                   file=sys.stderr)
--> 445         return method(match, context, next_state)
    446 else:
    447     if self.debug:

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/parsers/rst/states.py:1170, in Body.indent(self, match, context, next_state)
   1167 """Block quote."""
   1168 (indented, indent, line_offset, blank_finish
   1169  ) = self.state_machine.get_indented()
-> 1170 elements = self.block_quote(indented, line_offset)
   1171 self.parent += elements
   1172 if not blank_finish:

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/parsers/rst/states.py:1187, in Body.block_quote(self, indented, line_offset)
   1180 (blockquote.source, blockquote.line
   1181  ) = self.state_machine.get_source_and_line(line_offset+1)
   1182 (blockquote_lines,
   1183  attribution_lines,
   1184  attribution_offset,
   1185  indented,
   1186  new_line_offset) = self.split_attribution(indented, line_offset)
-> 1187 self.nested_parse(blockquote_lines, line_offset, blockquote)
   1188 elements.append(blockquote)
   1189 if attribution_lines:

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/parsers/rst/states.py:279, in RSTState.nested_parse(self, block, input_offset, node, match_titles, state_machine_class, state_machine_kwargs)
    276 if not state_machine:
    277     state_machine = state_machine_class(debug=self.debug,
    278                                         **state_machine_kwargs)
--> 279 state_machine.run(block, input_offset, memo=self.memo,
    280                   node=node, match_titles=match_titles)
    281 if use_default == 2:
    282     self.nested_sm_cache.append(state_machine)

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/parsers/rst/states.py:195, in NestedStateMachine.run(self, input_lines, input_offset, memo, node, match_titles)
    193 self.language = memo.language
    194 self.node = node
--> 195 results = StateMachineWS.run(self, input_lines, input_offset)
    196 assert results == [], ('NestedStateMachine.run() results should be '
    197                        'empty!')
    198 return results

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/statemachine.py:233, in StateMachine.run(self, input_lines, input_offset, context, input_source, initial_state)
    228         source, offset = self.input_lines.info(
    229             self.line_offset)
    230         print(f'\nStateMachine.run: line '
    231               f'(source={source!r}, offset={offset!r}):\n'
    232               f'| {self.line}', file=sys.stderr)
--> 233     context, next_state, result = self.check_line(
    234         context, state, transitions)
    235 except EOFError:
    236     if self.debug:

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/statemachine.py:445, in StateMachine.check_line(self, context, state, transitions)
    441         if self.debug:
    442             print('\nStateMachine.check_line: Matched transition '
    443                   f'"{name}" in state "{state.__class__.__name__}".',
    444                   file=sys.stderr)
--> 445         return method(match, context, next_state)
    446 else:
    447     if self.debug:

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/parsers/rst/states.py:2781, in Text.underline(self, match, context, next_state)
   2776 src, srcline = self.state_machine.get_source_and_line()
   2777 # TODO: why is abs_line_number() == srcline+1
   2778 # if the error is in a table (try with test_tables.py)?
   2779 # print("get_source_and_line", srcline)
   2780 # print("abs_line_number", self.state_machine.abs_line_number())
-> 2781 msg = self.reporter.severe(
   2782     'Unexpected section title.',
   2783     nodes.literal_block(blocktext, blocktext),
   2784     source=src, line=srcline)
   2785 self.parent += messages
   2786 self.parent += msg

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/utils/__init__.py:239, in Reporter.severe(self, *args, **kwargs)
    233 def severe(self, *args, **kwargs):
    234     """
    235     Level-4, "SEVERE": a severe error that must be addressed. If ignored,
    236     the output will contain severe errors. Typically level-4 system
    237     messages are turned into exceptions which halt processing.
    238     """
--> 239     return self.system_message(self.SEVERE_LEVEL, *args, **kwargs)

File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/docutils/utils/__init__.py:197, in Reporter.system_message(self, level, message, *children, **kwargs)
    195     self.stream.write(msg.astext() + '\n')
    196 if level >= self.halt_level:
--> 197     raise SystemMessage(msg, level)
    198 if level > self.DEBUG_LEVEL or self.debug_flag:
    199     self.notify_observers(msg)

SystemMessage: <string>:71: (SEVERE/4) Unexpected section title.

Arguments
---------