First, we'll import emigrate. We'll also import ionize, because it contains the Ion and Solution objects that we will use to set the initial conditions We'll also import numpy to set up some vectors, and cProfile for code profiling
In [1]:
import emigrate
import ionize
import cProfile
import time
# from matplotlib import pyplot as plot
from matplotlib.pyplot import *
%matplotlib inline
To define an initial condition, use the emigrate.Electrolyte class. An Electrolyte represents a quasi-1D system of solutions in a channel. It has a set of nodes, and each node represents a point along the axial dimension. Each point has a concentration for each Ion in the system. It can also have other attributes, such as a cross-sectional area, a pH, and an electric field. Only nodes, ions, and concentrations are mandatory. Other attributes are optional.
The easiest way of initializing an electrolyte is to create a set of solutions, and then creating a
In [2]:
solutions = [ionize.Solution(['hepes', 'tris'], [.05, .105]),
ionize.Solution(['caproic acid', 'tris', 'fluorescein', 'alexa fluor 488', 'mops', 'acetic acid'],
[.01, .1, .01, .01, .01, .01]),
ionize.Solution(['hydrochloric acid', 'tris'], [.04, .08]),
]
system = emigrate.Frame(dict(
n_nodes=137,
lengths=[.005, .001, .02],
interface_length=.0005,
solutions=solutions,
current=-500.,
))
# Plot the electrolyte concentrations.
for i in range(len(system.ions)):
plot(system.nodes, system.concentrations[i,:], '-o')
xlabel('x (m)')
ylabel('concentration (M)')
xlim([min(system.nodes), max(system.nodes)])
show()
In [3]:
solver = emigrate.Solver(system, precondition=True, flux_mode='slip')
tmax = 200
dt = 1
epoch = time.time()
sequence = solver.solve('examples/example_1.hdf5', dt, tmax)
print 'Solved in {:.2f} seconds.'.format(time.time()-epoch)
The solution resides in an Electromigration inside the Migrate object. Here, this object is solver.electromigration. Electromigration objects are iterable, so we can plot each concentration profile from them. In this case, that's somewhat unhelpful since there are so many solutions.
In [4]:
figure()
for frame in sequence:
for ion_concentration in frame.concentrations:
plot(frame.nodes, ion_concentration, '-')
xlabel('x (mm)')
ylabel('concentration (M)')
ylim([0, .2])
show()
However, the electromigration essentially acts as a list of frames, so we can also just plot an individual frame.
In [5]:
figure()
frame = sequence[100]
for ion_concentration in frame.concentrations:
plot(frame.nodes, ion_concentration, '-')
xlabel('x (m)')
ylabel('concentration (M)')
xlim([min(system.nodes), max(system.nodes)])
show()
figure()
plot(frame.nodes, frame.pH, '-')
xlabel('x (m)')
ylabel('pH')
xlim([min(system.nodes), max(system.nodes)])
show()
The solver loads two types of modules:
By default, the flux module called is the compact solver with no adaptive grid. The equilibrium solver called is the fixed pH solver.
In [6]:
solutions = [ionize.Solution(['acetic acid', 'b-alanine'], [.02, .012]),
ionize.Solution(['acetic acid', 'pyridine', 'aniline'], [.02, .009/2, .011/2]),
ionize.Solution(['acetic acid', 'sodium'], [.02, .018]),
]
system = emigrate.Frame(dict(lengths=[.01, .004, .01],
n_nodes=100,
interface_length=.0005,
solutions=solutions,
current=500,
domain_mode='left',
))
for i in range(len(system.ions)):
plot(system.nodes, system.concentrations[i,:])
xlabel('x (m)')
ylabel('concentration (M)')
show()
In [7]:
solver = emigrate.Solver(system, precondition=True, flux_mode='slip')
tmax = 80
dt = 1
solver.set_reference_frame(ionize.load_ion('acetic acid'), 'right')
epoch = time.time()
sequence = solver.solve('examples/example_2.hdf5', dt, tmax)
print 'Solved in {:.2f} seconds.'.format(time.time()-epoch)
In [8]:
figure()
frame = sequence[80]
for ion_concentration in frame.concentrations:
plot(frame.nodes, ion_concentration, '-')
xlabel('x (m)')
ylabel('concentration (M)')
xlim([min(frame.nodes), max(frame.nodes)])
ylim([0, .05])
show()
The default method for saving is to write to an HDF5 binary file. If a filename is specified when initializing the Migration, then the each frame will be saved to that HDF5 file as soon as it is computed. We can re-open these HDF5 files and get solutions on demand.
These HDF5 files can also be opened with the Emigrate application.
In [9]:
# Work with HDF5 file.
If JSON objects are desired, both electromigrations and electrolytes can be written in JSON format. However, beware when doing this for the electromigrations, as the file size can be very large.
In [10]:
# solver.electromigration.write_json('tutorial_example_5.json')
Solutions can then be reloaded using the Electromigration class. Currently, they lose all ion information except name during this process.
In [11]:
# solution_reloaded = emigrate.Electromigration([]).load_json('tutorial_example.json')
# print solution_reloaded.ions
# for t, electrolyte in solution_reloaded.electrolytes.items():
# for ion_concentration in electrolyte.concentrations:
# plot(electrolyte.nodes*1000, ion_concentration, '-')
# xlabel('x (mm)')
# ylabel('concentration (M)')
# show()
Instead of saving to file, json objects can simply be generated as text using the "serialize" command, and those objects can be deserialized to return the original object.
In [12]:
solutions = [ionize.Solution(['caproic acid', 'tris'], [.0075, .015]),
ionize.Solution(['hydrochloric acid', 'tris', 'alexa fluor 488', 'rhodamine 6g'],
[.005, .01, .0001, .0001]),
ionize.Solution(['hydrochloric acid', 'bis-tris'], [.0075, .015])
]
system = emigrate.Frame(dict(lengths=[0.01]*len(solutions),
n_nodes=200,
interface_length=.0005,
solutions=solutions,
# voltage= -50.,
current=-200,
domain_mode='left'
))
for i in range(len(system.ions)):
plot(system.nodes, system.concentrations[i,:])
xlabel('x (m)')
ylabel('concentration (M)')
show()
In [13]:
# solver.electromigration.hdf5.close()
solver = emigrate.Solver(system, precondition=True, flux_mode='slip')
tmax = 100
dt = .1
epoch = time.time()
sequence = solver.solve('examples/countermigrating.hdf5', dt, tmax)
print 'Solved in {} seconds.'.format(time.time()-epoch)
In [14]:
for frame in sequence:
for ion_concentration in frame.concentrations:
plot(frame.nodes, ion_concentration, '-')
xlabel('x (mm)')
ylabel('concentration (M)')
show()
figure()
for frame in sequence:
plot(frame.nodes, frame.pH, '-')
xlabel('x (mm)')
ylabel('pH')
show()
In [15]:
separation_buffer = ionize.Solution(['tris', 'hydrochloric acid'], [.01, .005])
solutions = [separation_buffer,
separation_buffer + ionize.Solution(['alexa fluor 488'], [.001]),
separation_buffer]
system = emigrate.Frame(dict(lengths=[.01, .001, .089],
n_nodes=100,
interface_length=.0005,
solutions=solutions,
current=-500,
domain_mode='left',
))
for i in range(len(system.ions)):
plot(system.nodes, system.concentrations[i,:])
xlabel('x (m)')
ylabel('concentration (M)')
show()
In [16]:
solver = emigrate.Solver(system, precondition=False, flux_mode='slip')
tmax = 200
dt = 1
epoch = time.time()
sequence = solver.solve('examples/example_4.hdf5', dt, tmax)
print 'Solved in {:.2f} seconds.'.format(time.time()-epoch)
In [17]:
water = ionize.Solution()
solutions = [ionize.Solution(['tris', 'hydrochloric acid'], [.01, .01]),
ionize.Solution(['hydrochloric acid'], [.01])]
system = emigrate.Frame(dict(lengths=[.01, .01],
n_nodes=100,
interface_length=.0005,
solutions=solutions,
current=-50,
domain_mode='left',
))
# for i in range(len(system.ions)):
# plot(system.nodes, system.concentrations[i,:])
# xlabel('x (m)')
# ylabel('concentration (M)')
# show()
In [18]:
solver = emigrate.Solver(system, precondition=True, flux_mode='slip')
tmax = 200
dt = 1
epoch = time.time()
sequence = solver.solve('examples/example_5a.hdf5', dt, tmax)
print 'Solved in {:.2f} seconds.'.format(time.time()-epoch)