Commit 5626bfe8 authored by Theresa Pollinger's avatar Theresa Pollinger
Browse files

proper error output in jupyter notebooks

parent de2b9abb
...@@ -30,9 +30,10 @@ class Interview(cmd.Cmd): ...@@ -30,9 +30,10 @@ class Interview(cmd.Cmd):
# Initialize cmd member variables # Initialize cmd member variables
self.myname = 'TheInterview' self.myname = 'TheInterview'
self.username = 'user' self.username = 'user'
self.intro = "Hello, " + self.username + "! I am " + self.myname + ", your partial differential equations and simulations expert. " \ self.intro = "Hello, " + self.username + "! I am " + self.myname + \
"Let's set up a simulation together.\n" \ ", your partial differential equations and simulations expert. " \
"How many dimensions does your model have?" "Let's set up a simulation together.\n" \
"Please enter anything to start the interview."
# self.greeting() # self.greeting()
self.update_prompt() self.update_prompt()
...@@ -60,33 +61,34 @@ class Interview(cmd.Cmd): ...@@ -60,33 +61,34 @@ class Interview(cmd.Cmd):
#self.state_machine.exaout.create_output(self.state_machine.simdata) #self.state_machine.exaout.create_output(self.state_machine.simdata)
raise raise
def please_prompt(self, query, if_yes, if_no=None): def please_prompt(self, query, if_yes, if_no=None, pass_other=False):
self.poutput(str(query) + " [y/n]? ") self.poutput(str(query) + " [y/n]? ")
self.state_machine.prompted = True self.state_machine.prompted = True
self.state_machine.if_yes = if_yes self.state_machine.if_yes = if_yes
self.state_machine.if_no = if_no self.state_machine.if_no = if_no
self.state_machine.pass_other = pass_other
def prompt_input_handling(self, arg): def prompt_input_handling(self, arg):
""" If we asked for a yes-no answer, execute what was specified in please_prompt. """ If we asked for a yes-no answer, execute what was specified in please_prompt.
return true if the input was handled here, and false if not.""" return true if the input was handled here, and false if not."""
if self.state_machine.prompted: if self.state_machine.prompted:
if arg == "": if arg == "":
self.poutput("Yes")
ret = True ret = True
else: else:
try: try:
ret = strtobool(str(arg).strip().lower()) ret = strtobool(str(arg).strip().lower())
except ValueError: except ValueError:
if self.state_machine.pass_other:
return False
# or use as input to callback an input processing fcn..? # or use as input to callback an input processing fcn..?
self.poutput("Please answer with Y/n") self.poutput("Please answer with y/n")
return True return True
self.state_machine.prompted = False self.state_machine.prompted = False
if ret: if ret:
self.state_machine.if_yes() if self.state_machine.if_yes is not None:
self.state_machine.if_yes()
elif self.state_machine.if_no is not None: elif self.state_machine.if_no is not None:
self.state_machine.if_no() self.state_machine.if_no()
else:
return False
return True return True
return False return False
......
...@@ -17,7 +17,7 @@ from pde_state_machine import * ...@@ -17,7 +17,7 @@ from pde_state_machine import *
# This "main class" is two things: a REPL loop, by subclassing the cmd2 Cmd class # This "main class" is two things: a REPL loop, by subclassing the cmd2 Cmd class
# and a state machine as given by the pytransitions package # and a state machine as given by the pytransitions package
class Interview(Kernel): class Interview(Kernel):
implementation = 'Echo' implementation = 'Interview'
implementation_version = '1.0' implementation_version = '1.0'
language = 'no-op' language = 'no-op'
language_version = '0.1' language_version = '0.1'
...@@ -26,7 +26,11 @@ class Interview(Kernel): ...@@ -26,7 +26,11 @@ class Interview(Kernel):
'mimetype': 'text/plain', 'mimetype': 'text/plain',
'file_extension': '.txt', 'file_extension': '.txt',
} }
banner = "Echo kernel - as useful as a parrot" banner = "Interview kernel\n\n" \
"Hello, " + "user" + "! I am " + "TheInterview" + ", your partial differential equations and simulations expert. " \
"Let's set up a simulation together.\n" \
"Please enter anything to start the interview."
# "How many dimensions does your model have?" #TODO this never shows in the notebook
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
...@@ -37,10 +41,12 @@ class Interview(Kernel): ...@@ -37,10 +41,12 @@ class Interview(Kernel):
self.update_prompt() self.update_prompt()
self.poutstring = ""# to collect string output to send self.poutstring = ""# to collect string output to send
self.outstream_name = 'stdout'
def poutput(self, text): def poutput(self, text, outstream_name='stdout'):
"""Accumulate the output here""" """Accumulate the output here"""
self.poutstring += str(text) + "\n" self.poutstring += str(text) + "\n"
self.outstream_name = outstream_name
############# input processing if not explain or undo ############# input processing if not explain or undo
def do_execute(self, code, silent, store_history=True, user_expressions=None, def do_execute(self, code, silent, store_history=True, user_expressions=None,
...@@ -52,10 +58,11 @@ class Interview(Kernel): ...@@ -52,10 +58,11 @@ class Interview(Kernel):
self.state_input_handling(arg) self.state_input_handling(arg)
if not silent: if not silent:
stream_content = {'name': 'stdout', 'text': self.poutstring} stream_content = {'name': self.outstream_name, 'text': self.poutstring}
self.send_response(self.iopub_socket, 'stream', stream_content) self.send_response(self.iopub_socket, 'stream', stream_content)
self.poutstring = "" self.poutstring = ""
self.outstream_name = 'stdout'
return {'status': 'ok', return {'status': 'ok',
# The base class increments the execution count # The base class increments the execution count
...@@ -70,14 +77,15 @@ class Interview(Kernel): ...@@ -70,14 +77,15 @@ class Interview(Kernel):
try: try:
self.state_machine.stateDependentInputHandling[self.state_machine.state](arg) self.state_machine.stateDependentInputHandling[self.state_machine.state](arg)
except Exception as error: except Exception as error:
#self.exaout.create_output(self.simdata) #self.state_machine.exaout.create_output(self.simdata)
raise raise
def please_prompt(self, query, if_yes, if_no=None): def please_prompt(self, query, if_yes, if_no=None, pass_other=False):
self.poutput(str(query) + " [y/n]? ") self.poutput(str(query) + " [y/n]? ")
self.state_machine.prompted = True self.state_machine.prompted = True
self.state_machine.if_yes = if_yes self.state_machine.if_yes = if_yes
self.state_machine.if_no = if_no self.state_machine.if_no = if_no
self.state_machine.pass_other = pass_other
def prompt_input_handling(self, arg): def prompt_input_handling(self, arg):
""" If we asked for a yes-no answer, execute what was specified in please_prompt. """ If we asked for a yes-no answer, execute what was specified in please_prompt.
...@@ -89,16 +97,17 @@ class Interview(Kernel): ...@@ -89,16 +97,17 @@ class Interview(Kernel):
try: try:
ret = strtobool(str(arg).strip().lower()) ret = strtobool(str(arg).strip().lower())
except ValueError: except ValueError:
if self.state_machine.pass_other:
return False
# or use as input to callback an input processing fcn..? # or use as input to callback an input processing fcn..?
self.poutput("Please answer with y/n") self.poutput("Please answer with y/n")
return True return True
self.state_machine.prompted = False self.state_machine.prompted = False
if ret: if ret:
self.state_machine.if_yes() if self.state_machine.if_yes is not None:
self.state_machine.if_yes()
elif self.state_machine.if_no is not None: elif self.state_machine.if_no is not None:
self.state_machine.if_no() self.state_machine.if_no()
else:
return False
return True return True
return False return False
......
...@@ -142,7 +142,7 @@ class MMTInterface: ...@@ -142,7 +142,7 @@ class MMTInterface:
self.extension = ':interview' self.extension = ':interview'
self.URIprefix = 'http://mathhub.info/' self.URIprefix = 'http://mathhub.info/'
self.namespace = 'MitM/smglom/calculus' # TODO self.namespace = 'MitM/smglom/calculus' # TODO
self.debugprint = True self.debugprint = False
# try: # try:
# _thread.start_new_thread(run_mmt_server, ()) # _thread.start_new_thread(run_mmt_server, ())
# except: # except:
......
...@@ -4,9 +4,6 @@ ...@@ -4,9 +4,6 @@
from transitions import Machine, State from transitions import Machine, State
from collections import OrderedDict from collections import OrderedDict
# strings: # strings:
# http://mattoc.com/python-yes-no-prompt-cli.html
from distutils.util import strtobool
import pyparsing as pp
import re import re
from string_handling import * from string_handling import *
...@@ -15,17 +12,21 @@ from mmtinterface import * ...@@ -15,17 +12,21 @@ from mmtinterface import *
class InterviewError(Exception): class InterviewError(Exception):
"""Errors that occur during the course of the interview and are not due to mmt server errors"""
def __init__(self, err): def __init__(self, err):
self.error = err self.error = err
super(InterviewError, self).__init__("Interview error: " + str(self.error)) super(InterviewError, self).__init__("Interview error: " + str(self.error))
###For the part of the simdata whose contents will be cleaned up if there was an error
###to be used in with statements
class CriticalSubdict(): class CriticalSubdict():
def __init__(self, subdict): def __init__(self, subdict, output_function=print, outermost=True):
"""The sub-part of subdict that needs to be restored if something goes wrong"""
"""To be used in with-statements"""
"""Catches errors only if it is the outermost one"""
self.subdict = subdict self.subdict = subdict
self.initial_subdict = self.subdict.copy() self.initial_subdict = self.subdict.copy()
self.output_function = output_function
self.outermost = outermost
def __enter__(self): def __enter__(self):
return self.subdict return self.subdict
...@@ -36,8 +37,8 @@ class CriticalSubdict(): ...@@ -36,8 +37,8 @@ class CriticalSubdict():
self.subdict.clear() self.subdict.clear()
for key in self.initial_subdict: for key in self.initial_subdict:
self.subdict[key] = self.initial_subdict[key] self.subdict[key] = self.initial_subdict[key]
print(value) # handling: give feedback, only if our own error, and the outermost subdict
if isinstance(value, MMTServerError) or isinstance(value, InterviewError): if (isinstance(value, MMTServerError) or isinstance(value, InterviewError)) and self.outermost:
self.please_repeat(value.args[0]) self.please_repeat(value.args[0])
return True return True
else: else:
...@@ -48,12 +49,11 @@ class CriticalSubdict(): ...@@ -48,12 +49,11 @@ class CriticalSubdict():
append = "" append = ""
if moreinfo: if moreinfo:
append = "\nDetails: " + moreinfo append = "\nDetails: " + moreinfo
print("I did not catch that. Could you please rephrase?" + append) self.output_function("I did not catch that. Could you please rephrase?" + append, 'stderr')
# This "main class" is two things: a REPL loop, by subclassing the cmd2 Cmd class
# and a state machine as given by the pytransitions package
class PDE_States: class PDE_States:
"""Just a state machine using pytranisitions that walks our theory graph and creates ephemeral theories"""
def __init__(self, output_function, after_state_change_function, prompt_function): def __init__(self, output_function, after_state_change_function, prompt_function):
# just act like we were getting the right replies from MMT # just act like we were getting the right replies from MMT
self.cheating = True self.cheating = True
...@@ -63,7 +63,7 @@ class PDE_States: ...@@ -63,7 +63,7 @@ class PDE_States:
# Initialize a state machine # Initialize a state machine
states = [ states = [
# State('greeting'), State('greeting'),
State('dimensions', on_enter=['dimensions_begin']), State('dimensions', on_enter=['dimensions_begin']),
State('domain', on_enter=['domain_begin'], on_exit=['domain_exit']), State('domain', on_enter=['domain_begin'], on_exit=['domain_exit']),
State('unknowns', on_enter=['unknowns_begin'], on_exit=['unknowns_exit']), State('unknowns', on_enter=['unknowns_begin'], on_exit=['unknowns_exit']),
...@@ -79,29 +79,21 @@ class PDE_States: ...@@ -79,29 +79,21 @@ class PDE_States:
self.machine.add_ordered_transitions( self.machine.add_ordered_transitions(
trigger='last_state') # TODO do something to avoid going back from the first state trigger='last_state') # TODO do something to avoid going back from the first state
# self.to_dimensions() # self.to_dimensions()
# self.machine.add_transition(trigger='greeting_over', source='greeting', dest='dimensions') self.machine.add_transition(trigger='greeting_over', source='greeting', dest='dimensions')
self.machine.add_transition(trigger='dimensions_parsed', source='dimensions', dest='domain', self.machine.add_transition(trigger='dimensions_parsed', source='dimensions', dest='domain',
before='print_empty_line') before='print_empty_line')
self.machine.add_transition(trigger='domain_parsed', source='domain', dest='unknowns', self.machine.add_transition(trigger='domain_parsed', source='domain', dest='unknowns',
before='print_empty_line') before='print_empty_line')
self.machine.add_transition(trigger='unknowns_parsed', source='unknowns', dest='parameters', self.machine.add_transition(trigger='unknowns_parsed', source='unknowns', dest='parameters')
after='print_empty_line') self.machine.add_transition(trigger='parameters_parsed', source='parameters', dest='pdes')
self.machine.add_transition(trigger='parameters_parsed', source='parameters', dest='pdes',
after='print_empty_line')
self.machine.add_transition(trigger='pdes_parsed', source='pdes', dest='bcs', before='print_empty_line') self.machine.add_transition(trigger='pdes_parsed', source='pdes', dest='bcs', before='print_empty_line')
self.machine.add_transition(trigger='bcs_parsed', source='bcs', dest='sim', before='print_empty_line') self.machine.add_transition(trigger='bcs_parsed', source='bcs', dest='sim', before='print_empty_line')
#self.machine.add_transition(trigger='props_parsed', source='props', dest='sim', before='print_empty_line')#TODO props #self.machine.add_transition(trigger='props_parsed', source='props', dest='sim', before='print_empty_line')#TODO props
self.machine.add_transition(trigger='sim_finished', source='sim', dest='sim', before='print_empty_line') self.machine.add_transition(trigger='sim_finished', source='sim', dest='sim', before='print_empty_line')
# Initialize cmd member variables
self.myname = 'TheInterview'
self.username = 'user'
self.intro = "Hello, " + self.username + "! I am " + self.myname + ", your partial differential equations and simulations expert. " \
"Let's set up a simulation together.\n" \
"How many dimensions does your model have?"
# define what happens when input is received in a certain state # define what happens when input is received in a certain state
self.stateDependentInputHandling = { self.stateDependentInputHandling = {
'greeting': self.greeting_handle_input,
'dimensions': self.dimensions_handle_input, 'dimensions': self.dimensions_handle_input,
'domain': self.domain_handle_input, 'domain': self.domain_handle_input,
'unknowns': self.unknowns_handle_input, 'unknowns': self.unknowns_handle_input,
...@@ -273,12 +265,20 @@ class PDE_States: ...@@ -273,12 +265,20 @@ class PDE_States:
} }
self.exaout = ExaOutput() self.exaout = ExaOutput()
"""Variables to signal callbacks depending on yes/no prompts"""
self.prompted = False self.prompted = False
self.if_yes = None self.if_yes = None
self.if_no = None self.if_no = None
self.pass_other = False
def greeting_handle_input(self, userstring):
self.greeting_over()
##### for state dimensions ##### for state dimensions
def dimensions_begin(self): def dimensions_begin(self):
self.poutput("Hello, user! I am TheInterview, your partial differential equations and simulations expert. "
"Let's set up a simulation together.")
self.poutput("How many dimensions does your model have?") self.poutput("How many dimensions does your model have?")
self.poutput("I am just assuming it's 1, since that is all we can currently handle.") # TODO self.poutput("I am just assuming it's 1, since that is all we can currently handle.") # TODO
self.simdata["num_dimensions"] = 1 self.simdata["num_dimensions"] = 1
...@@ -315,16 +315,15 @@ class PDE_States: ...@@ -315,16 +315,15 @@ class PDE_States:
def domain_handle_input(self, userstring): def domain_handle_input(self, userstring):
domain_name = get_first_word(userstring) domain_name = get_first_word(userstring)
# subdict = self.simdata[self.state] # subdict = self.simdata[self.state]
with CriticalSubdict(self.simdata[self.state]) as subdict: with CriticalSubdict(self.simdata[self.state], self.poutput) as subdict:
parsestring = userstring parsestring = userstring
mmtreply = self.mmtinterface.mmt_new_decl(domain_name, subdict["theoryname"], parsestring) mmtreply = self.mmtinterface.mmt_new_decl(domain_name, subdict["theoryname"], parsestring)
mmttype = self.mmtinterface.mmt_infer_type(subdict["theoryname"], domain_name) mmttype = self.mmtinterface.mmt_infer_type(subdict["theoryname"], domain_name)
if mmttype.inferred_type_to_string() != "type": if mmttype.inferred_type_to_string() != "type":
raise InterviewError("This seems to not be a type. It should be!") raise InterviewError("This seems to not be a type. It should be!")
result = self.mmtinterface.query_for(subdict["theoryname"]) # if not self.cheating else result = self.mmtinterface.query_for(subdict["theoryname"])
#print(result.tostring())
subdict["name"] = domain_name subdict["name"] = domain_name
(fro, to) = mmtreply.getIntervalBoundaries(result, domain_name) #if not self.cheating else (0.0, 1.0) # todo make work again (fro, to) = mmtreply.getIntervalBoundaries(result, domain_name)
subdict["axes"]["x_1"] = "[" + str(fro) + ";" + str(to) + "]" subdict["axes"]["x_1"] = "[" + str(fro) + ";" + str(to) + "]"
(subdict["from"], subdict["to"]) = (fro, to) (subdict["from"], subdict["to"]) = (fro, to)
...@@ -342,7 +341,7 @@ class PDE_States: ...@@ -342,7 +341,7 @@ class PDE_States:
# (ok, root) = self.mmtinterface.query_for(self.simdata[self.state]["theoryname"]) # (ok, root) = self.mmtinterface.query_for(self.simdata[self.state]["theoryname"])
def domain_mmt_postamble(self): def domain_mmt_postamble(self):
with CriticalSubdict(self.simdata[self.state]) as subdict: with CriticalSubdict(self.simdata[self.state], self.poutput) as subdict:
subdict["boundary_name"] = subdict["name"] #todo subdict["boundary_name"] = subdict["name"] #todo
if not self.cheating: if not self.cheating:
self.mmtinterface.mmt_new_decl('mydomainpred', subdict["theoryname"], self.mmtinterface.mmt_new_decl('mydomainpred', subdict["theoryname"],
...@@ -375,7 +374,7 @@ class PDE_States: ...@@ -375,7 +374,7 @@ class PDE_States:
userstring.replace(self.simdata["domain"]["name"], userstring.replace(self.simdata["domain"]["name"],
"pred myDomainPred") if not self.cheating else userstring) "pred myDomainPred") if not self.cheating else userstring)
with CriticalSubdict(self.simdata[self.state]) as usubdict: with CriticalSubdict(self.simdata[self.state], self.poutput) as usubdict:
# create mmt theory with includes # create mmt theory with includes
once = self.new_theory(unknown_name) once = self.new_theory(unknown_name)
# self.include_in(unknown_name, self.simdata["domain"]["theoryname"]) # self.include_in(unknown_name, self.simdata["domain"]["theoryname"])
...@@ -392,7 +391,7 @@ class PDE_States: ...@@ -392,7 +391,7 @@ class PDE_States:
"type": type, "type": type,
"codomain": type.replace(self.simdata["domain"]["name"] + " →", "", 1).strip(), "codomain": type.replace(self.simdata["domain"]["name"] + " →", "", 1).strip(),
} }
with CriticalSubdict(self.simdata["unknowns"][unknown_name]) as subdict: with CriticalSubdict(self.simdata["unknowns"][unknown_name], self.poutput, False) as subdict:
if self.mmtinterface.query_for(unknown_name + "_to_go_to_trash").hasDefinition(unknown_name): if self.mmtinterface.query_for(unknown_name + "_to_go_to_trash").hasDefinition(unknown_name):
raise InterviewError("Unknowns cannot be defined!") raise InterviewError("Unknowns cannot be defined!")
if not type_is_function_from(subdict["type"], self.simdata["domain"]["name"]): if not type_is_function_from(subdict["type"], self.simdata["domain"]["name"]):
...@@ -407,12 +406,13 @@ class PDE_States: ...@@ -407,12 +406,13 @@ class PDE_States:
self.mmtinterface.mmt_new_decl("codomain", subdict["viewname"], "ucodomain = " + subdict["codomain"]) self.mmtinterface.mmt_new_decl("codomain", subdict["viewname"], "ucodomain = " + subdict["codomain"])
self.mmtinterface.mmt_new_decl("unktype", subdict["viewname"], "unknowntype = myUnkType") self.mmtinterface.mmt_new_decl("unktype", subdict["viewname"], "unknowntype = myUnkType")
self.poutput("Ok, " + userstring) self.poutput("Ok, " + userstring)
#if self.please_prompt("Are these all the unknowns?"): #TODO #self.please_prompt("Are these all the unknowns?", lambda: self.trigger('unknowns_parsed'), pass_other=True) #TODO
self.trigger('unknowns_parsed') self.trigger('unknowns_parsed')
def unknowns_exit(self): def unknowns_exit(self):
for unknown in self.simdata["unknowns"]: for unknown in self.simdata["unknowns"]:
self.poutput(self.simdata["unknowns"][unknown]["string"]) self.poutput(self.simdata["unknowns"][unknown]["string"])
self.print_empty_line()
##### for state parameters ##### for state parameters
def parameters_begin(self): def parameters_begin(self):
...@@ -427,9 +427,9 @@ class PDE_States: ...@@ -427,9 +427,9 @@ class PDE_States:
return return
parameter_name = get_first_word(userstring) parameter_name = get_first_word(userstring)
with CriticalSubdict(self.simdata["parameters"]) as psubdict: with CriticalSubdict(self.simdata["parameters"], self.poutput) as psubdict:
self.simdata["parameters"][parameter_name] = {} psubdict[parameter_name] = {}
with CriticalSubdict(self.simdata["parameters"][parameter_name]) as subdict: with CriticalSubdict(self.simdata["parameters"][parameter_name], self.poutput, False) as subdict:
# create mmt theory # create mmt theory
self.new_theory(parameter_name) self.new_theory(parameter_name)
# we might need the other parameters created so far, so use them # we might need the other parameters created so far, so use them
...@@ -459,12 +459,13 @@ class PDE_States: ...@@ -459,12 +459,13 @@ class PDE_States:
self.mmtinterface.mmt_new_decl("param", subdict["viewname"], self.mmtinterface.mmt_new_decl("param", subdict["viewname"],
"param = " + parameter_name) "param = " + parameter_name)
self.poutput("Ok, " + parsestring) self.poutput("Ok, " + parsestring)
self.please_prompt("Are these all the parameters?", lambda: self.trigger('parameters_parsed')) self.please_prompt("Would you like to declare more parameters?", None, lambda: self.trigger('parameters_parsed'), True)
def parameters_exit(self): def parameters_exit(self):
# print(str(self.simdata["parameters"])) # print(str(self.simdata["parameters"]))
for parameter in self.simdata["parameters"]: for parameter in self.simdata["parameters"]:
self.poutput(self.simdata["parameters"][parameter]["string"]) self.poutput(self.simdata["parameters"][parameter]["string"])
self.print_empty_line()
##### for state pdes ##### for state pdes
def pdes_begin(self): def pdes_begin(self):
...@@ -473,9 +474,9 @@ class PDE_States: ...@@ -473,9 +474,9 @@ class PDE_States:
self.simdata["pdes"]["pdes"] = [] self.simdata["pdes"]["pdes"] = []
def pdes_handle_input(self, userstring): def pdes_handle_input(self, userstring):
with CriticalSubdict(self.simdata["pdes"]["pdes"]) as psubdict: with CriticalSubdict(self.simdata["pdes"]["pdes"], self.poutput) as psubdict:
self.simdata["pdes"]["pdes"].append({}) psubdict.append({})
with CriticalSubdict(self.simdata["pdes"]["pdes"][-1]) as subdict: with CriticalSubdict(self.simdata["pdes"]["pdes"][-1], self.poutput, False) as subdict:
subdict["theoryname"] = "ephpde" + str(len(self.simdata["pdes"]["pdes"])) subdict["theoryname"] = "ephpde" + str(len(self.simdata["pdes"]["pdes"]))
self.new_theory(subdict["theoryname"]) self.new_theory(subdict["theoryname"])
...@@ -488,8 +489,8 @@ class PDE_States: ...@@ -488,8 +489,8 @@ class PDE_States:
# store the info # store the info
subdict["string"] = userstring subdict["string"] = userstring
subdict["lhsstring"] = parts[0].strip() subdict["lhsstring"] = parts[0].strip()
subdict["rhsstring"] = parts[1].strip()#TODO expand subdict["rhsstring"] = parts[1].strip()
subdict["rhsstring_expanded"] = self.try_expand(subdict["rhsstring"]) subdict["rhsstring_expanded"] = self.try_expand(subdict["rhsstring"])#TODO expand properly
# to make the left-hand side a function on x, place " [ variablename : domainname ] " in front # to make the left-hand side a function on x, place " [ variablename : domainname ] " in front
if parts[0].find("x") > -1: if parts[0].find("x") > -1:
...@@ -557,9 +558,9 @@ class PDE_States: ...@@ -557,9 +558,9 @@ class PDE_States:
##### for state bcs ##### for state bcs
def bcs_begin(self): def bcs_begin(self):
self.poutput("Let's discuss your boundary conditions. " self.poutput("Let's discuss your boundary conditions. "
"What do they look like? u(x) = f(x) or u(" + str(self.simdata["domain"]["to"]) + ") = \\alpha ?") #TODO remove square brakcets "What do they look like? u(x) = f(x) or u(" + str(self.simdata["domain"]["to"]) + ") = \\alpha ?")
bctypetheoryname = self.redefine_bcs() bctypetheoryname = self.redefine_bcs()
with CriticalSubdict(self.simdata["bcs"]) as subdict: with CriticalSubdict(self.simdata["bcs"], self.poutput) as subdict:
subdict["theoryname"] = "ephbcs" subdict["theoryname"] = "ephbcs"
subdict["bcs"] = [] subdict["bcs"] = []
self.new_theory(subdict["theoryname"]) self.new_theory(subdict["theoryname"])
...@@ -575,7 +576,7 @@ class PDE_States: ...@@ -575,7 +576,7 @@ class PDE_States:
subdict["measure_given"] = 0 subdict["measure_given"] = 0
def bcs_handle_input(self, userstring): def bcs_handle_input(self, userstring):
with CriticalSubdict(self.simdata["bcs"]) as subdict: with CriticalSubdict(self.simdata["bcs"], self.poutput) as subdict:
currentname = "bc" + str(len(subdict["bcs"])) currentname = "bc" + str(len(subdict["bcs"]))
subdict["bcs"].append({"name": currentname}) subdict["bcs"].append({"name": currentname})
# TODO use symbolic computation to order into LHS and RHS # TODO use symbolic computation to order into LHS and RHS
...@@ -625,7 +626,7 @@ class PDE_States: ...@@ -625,7 +626,7 @@ class PDE_States:
"firstBC = solutionat " + at_x + " is " + parts[1]) "firstBC = solutionat " + at_x + " is " + parts[1])