MEMS = MicroElectroMechanical Systems
They combine perception, computation, and actuation.
IC
Processes Oxidation Diffusion LPCVD Photolithography Epitaxy Sputtering Ion Implantation Etc. |
Micromachining
Processes Bulk Micromachining Surface Micromachining Wafer Bonding LIGA Deep Silicon Reactive Ion Etching Micromolding Etc. |
The MEMS Exchange will perform a process sequence in order to create a device. The process sequence can be spread across several individual fabrication facilities for the sake of process and design freedom.
The MEMS Exchange virtual fabrication network allows flexibility in:
First step toward building Web-based tools.
Checks a sequence for violations of several different rules.
Also graphically displays the layers being built up.
Features:
Note: ACID = Atomicity, Consistency, Isolation, Durability
from ZODB import DB from ZODB.FileStorage import FileStorage storage = FileStorage('/tmp/test-filestorage.fs') db = DB(storage) conn = db.open() root = conn.root() user_db = root['user_db'] newuser = User('amk') user_db.users['amk'] = newuser get_transaction().commit()
Replace FileStorage
with
BerkeleyStorage
to use a different low-level storage
mechanism.
ZEO consists of a ClientStorage
class which
retrieves objects over a socket, and a server that the
ClientStorage
can talk to.
That's it! There are a few rules to keep in mind, though...
import ZODB from Persistence import Persistent class User(Persistent): def __init__ (self): self.email = None self.names = [] def add_name (self, name): self.names.append(name) self._p_changed = 1
_p_changed
)isinstance()
, issubclass()
don't
work.__r*__
__setattr__
, __delattr__
must set
dirty bit manuallyEventually, an updated version of ZODB for Python 2.2 should make #2 and #3 go away.
<User at 0000000ef3: akuchlin> prefix/first/last/suffix: Mr/Andrew/Kuchling/ email: 'amk@amk.ca' address: <Address at 0000000f2d> ... _p_changed: false
<Address at 0000000f2d> street1/2/3: 1320 N. Veitch St., #608// city/state/zip: Arlington/VA/22201 ... _p_changed: false
ludwig akuchlin>opendb root databases available: process_lib run_db user_db ... other variables and functions: root commit() = get_transaction().commit() abort() = get_transaction().abort() >>> r = run_db.get_run(113) >>> r.owner <User at 839e2f8: akuchlin> >>> r.owner = user_db.get_user('gward') >>> r.owner <User at 83a0348: gward> >>> commit() # commit the transaction
(See Greg Ward's presentation in the Lightning Talk session tomorrow.)
class ProcessRun(MXPersistent): """ Instance attributes: run_id : int the unique identifier for this process run name : string the user-supplied name of this run owner : User # notnone the individual user who owns this run billed : DateTime | boolean whether or not we've billed the customer review_comments : PersistentList [Comment] An always-growing list of comments... """
Type-checking discovered database errors; here they are: run_db.runs[639].object_versions[6].sequence._key_map['S0002'].wafer_ids['W001'] .description.resistivity.unit.dims: expected attribute 'dimension_names' not found run_db.runs[639].object_versions[6].sequence._key_map['S0002'].wafer_ids['W001'] .description.resistivity.unit.dims: expected attribute 'num_dimensions' not found run_db.runs[639].object_versions[6].sequence._key_map['S0002'].wafer_ids['W001'] .description.resistivity.unit.dims: expected attribute 'dimension_powers' not found make: *** [check] Error 1
ute tools>MX_DB=file:/www/var/mxdb.fs python zodb_census.py opening database... expecting to see 306153 objects maximum expected OID: 00000abe43 OID: 00000abe44 (objects seen: 306153) census completed total OIDs attempted: 704068 empty slots seen: 397915 actual objects seen: 306153 objects seen by type: ActiveVersionCollection 963 Address 1861 AlignmentMark 51 BaseProcess 2324 BusinessDatabase 1 ... OOBTree 15 OOBucket 296 Parameter 29585 ParameterList 17966 ProcessHierarchy 1 ProcessLibrary 1 ProcessModule 840 ProcessRun 1885 ProcessSequence 1885 ProcessStep 16990 RunDatabase 1 ...
Builds an index of the references in the ZODB's object graph, and lets you explore it.
(Finding a bug, as demonstrated by Greg Ward on our internal mailing list)
First, a mystery:
$ opendb [...] >>> len(user_db.users) 775 $ make census [...] User 873
There are almost 100 more User objects in the ZODB than users
in our UserDatabase
object.
Let's list those 874 objects, sorted by user ID:
$ ./tools/zodb_index.py -C mems.access.user.User | sort -f -b +4 [...] 00000380d0: <User at 83805c8: akuchlin> 00000010ca: <User at 83278d8: gward> 0000000011: <User at 816cd18: Hexon> 000001a5d1: <User at 8332608: Hexon> 000001e4b1: <User at 833a138: Hexon> 0000021943: <User at 83437c0: Hexon> 0000023c4c: <User at 8346be8: Hexon> 00000317af: <User at 82c0578: Hexon> 00000010c9: <User at 83258d0: wbenard>
6 objects for the user "Hexon"?!?
Running zodb_index.py -r 0000000011
shows 251
refs to OID 11, so we'll guess that OID 11 is The One True User
Object for Hexon, and the others are impostors.
Let's dig deeper...
$ ./tools/zodb_index.py -r 1a5d1 1e4b1 21943 23c4c 317af 000001a5d1: <User at 81e4768: Hexon> 000001a5d0: <Review at 8220698> 000001a5d2: <FabProvider at 82248d0: UMich> 000001a5d2: <FabProvider at 82248d0: UMich> 000001a608: <Comment at 8231b88: Hexon> 0000060994: <Review at 8230a28> 0000060b00: <Comment at 822ff60: Hexon> 000001e4b1: <User at 8224550: Hexon> 000001e4b0: <Review at 8232308> 000001e4b2: <FabProvider at 822ff00: UMich> 000001e4b2: <FabProvider at 822ff00: UMich> 000001e5e7: <Comment at 8233138: Hexon> ...
zodb_index
-style indexing?)We may contribute some of our tools (opendb, MXBase?).
We have over 4000 tests for our basic objects. The existence of this test suite gives us confidence when we refactor the code.
Consider this simple function:
def f(s, val): if val < 0: raise ValueError, 'val cannot be negative' elif val == 42: print 'The answer!' return s * val
from sancho.unittest import TestScenario, \ parse_args, run_scenarios import module tested_modules = ['module'] class MyFunctionTest (TestScenario): def setup(self): pass def shutdown(self): pass def check_func(self): "Test the function's output: 6" # Test the null case (val == 0) self.test_val( "module.f('', 0)", '') self.test_val( "module.f('abc', 0)", '') # Test the identity (val == 1) self.test_val( "module.f('', 1)", '') self.test_val( "module.f('abc', 1)", 'abc') # Test a real case (val == 3) self.test_val( "module.f('', 3)", '') self.test_val( "module.f('abc', 3)", 'abcabcabc') if __name__ == "__main__": (scenarios, options) = parse_args() run_scenarios (scenarios, options)
Quixote is our environment for building Web applications.
Design goals:
Features:
An application is just a Python package whose name is
specified in a config file. (mems.ui
,
quixote.demo
, webapp
)
webapp/ __init__.py module1.py module2.py pages1.ptl pages2.ptl
A URL is mapped to a callable Python object by traversing objects starting from the base package.
http://www/ | calls | webapp._q_index |
http://www/simple | calls | webapp.simple |
http://www/run/ | calls | webapp.run._q_index |
__init__.py:
_q_exports = ["simple", "error", "widgets"] import sys from quixote.demo.pages import _q_index from quixote.demo.widgets import widgets from quixote.demo.integer_ui import IntegerUI def simple (request): # This function returns a plain text document, not HTML. request.response.set_content_type("text/plain") return "This is the Python function 'quixote.demo.simple'.\n"
request
wraps up:
It's derived from Zope's
HTTPRequest
/HTTPResponse
classes.
Most templating syntaxes look like HTML with a bit of additional syntax.
PHP |
<? for ($i=1; $i<10; $i++) print $i;> |
ASP |
<% addr = Request.form("email"); %> |
DTML | <dtml-var "row"> or <!--#var "row"--> |
Our syntax looks completely different, though still familiar...
When Python evaluates a lone expression, it discards the result:
def f(): string.lower('abc') return 1
In PTL, the result is converted to a string and appended to the output.
template numbers(n): for i in range(n): i " " # add whitespace
An import hook lets us import PTL files as if they're regular Python modules:
from quixote import enable_ptl enable_ptl() from webapp.pages import numbers
pages.ptl:
template _q_index(request): print "debug message from the index page" """ <html> <head><title>Quixote Demo</title></head> <body> <h1>Hello, world!</h1> """ "<table>" for i in range(10): make_row(i) "</table>" template make_row(num): "<tr><td colspan=%i>%i</td></tr>" % (num, num)
vi
and Emacs modes for
it._q_index (request)
: string
When traversal stops at a module or package, this is the default
function name that's tried.
_q_access (request)
When found along the way, this function is called and must not
raise an exception to let traversal continue.
_q_getname (request, component)
: object
When a name isn't found, _q_getname
will be called.
If it returns an object, traversal will continue with this
object.
Access control function; traversal can go no further if it raises an exception.
def _q_access (request): from mems.ui.lib.errors import NotLoggedInError if request.session.user is None: raise NotLoggedInError, \ ("You must be signed in to view runcards.")
This saves us from having to write checking code for every public function. Instead, we can just put an access restriction on the whole module.
"/run/200/" is a more readable URL than "/run/?run_id=200".
_q_getname
gets called with the current request
and the component of the URL path. If it returns an object,
traversal continues with that object.
mems/ui/run/__init__.py:
def _q_getname (request, component): return RunUI(request, component) class RunUI: _q_exports = ['details', 'check', ...] def __init__ (self, request, component): run_db = get_run_database() self.run = run_db.get_run(int(component)) template _q_index (self, request): # /run/200/ ... return index page ... template details (self, request): # /run/200/details/ ... return a more detailed page ...
An optional part of Quixote that lives in the
quixote.form
subpackage, the framework lets us
quickly implement basic (and not so basic) HTML forms.
Features:
Quixote, Sancho, Grouch:
http://www.mems-exchange.org/software/
Greg Ward will be talking about Grouch tomorrow.
More on the MX toolset:
http://www.amk.ca/python/writing/mx-architecture/
Join the quixote-users mailing list:
http://www.mems-exchange.org/mailman/listinfo/quixote-users/
These slides:
http://www.amk.ca/talks/