Tillmann,

I've added a jiffy script to synthesize pseudo-precession photos from a rotation dataset, to the latest PHENIX package. We build this package nightly, so any PHENIX bundle with a version number greater than "dev-402" will work....however I see that dev-402 is not yet on the public Web site (http://www.phenix-online.org) so I'll attach the python script to this email for standalone use.

Here's what you'll need:
1) Make sure any recent PHENIX is installed and on path.
2) Make sure Mosflm is on path as "ipmosflm"
3) Index using two frames in the dataset:

labelit.index /data/project/dataset1_1_E1_###.img 1 90

4) Generate the precession photo:

labelit.python precession_photo.py bravais_choice=1 \ #id number for the bravais setting as listed by labelit.index
     pixel_width=600 resolution_outer=3.0 intensity_full_scale=1000 \
     plot_section="H,K,0" image_range=1,90 pdf_output.file="HKL.pdf"

5) These command line options should be self explanatory, but "--help" gives a fuller description.

Nick Sauter

Tillmann Heinisch wrote:
Hi,
I have problems solving the structure of a protein crystal which seems to be 
disordered. In order to investigate the disorder it would be useful to have a 
precision photograph that shows reflections only in the [0kl] plane. Does 
anyone know software that can transform raw data to give intensity distribution 
in distinct zones of hkl?
Many Thanks for your help,
Tillmann

def usage():
  return """Python script to generate a synthetic photograph.
   Requirements:  Phenix must be installed and on path.
                  Mosflm must be installed and "ipmosflm" on path.

   Usage:
   1. First index the dataset using labelit.index.  Typical syntax to index two 
images is
      labelit.index /home/data/project/dataset1_1_E1_###.img 1 90

   2. Then

      labelit.precession_photo <command line arguments>

      Example:

      labelit.precession_photo bravais_choice=1 \\
      pixel_width=600 \\
      resolution_outer=3.0 \\
      intensity_full_scale=1000 \\
      plot_section="H,K,0" \\
      image_range=1,90 \\
      pdf_output.file="HKL.pdf"

   3. Command line arguments explained:

      labelit.precession_photo --help

   Known limitations:
   a) Since the source images are rotation photographs, there is an inherent
      approximation in assuming that the data was obtained at the central
      rotation angle (0.5 degree in a 0.0 to 1.0 rotation).
   b) Real precession photographs are obtained with a finite-width annulus;
      however the approximation here is one of an infinitesmal-width opening.
   c) This is a naive implementation that reads all of the data into memory
      first before calculating the image.  More efficient algorithms will be
      implemented later.

   Author: Nick Sauter, LBNL; May 8, 2010.
   Released under the CCTBX license; see cctbx.sf.net.
"""
import math,pickle,os
import libtbx.phil

precession_master_phil = libtbx.phil.parse("""
labelit_precession {
  pixel_width = 1500
    .type = int
    .help = "Width of pixel grid on which to calculate the synthesized image; 
must be sufficiently large to sample the Bragg spots"
  resolution_outer = 4.0
    .type = float
    .help = "The high-resolution limit (Angstroms) for the synthesized image"
  bravais_choice = None
    .type = int
    .help = "Crystal setting (integer ID#), as enumerated in labelit.index 
output, chosen for the synthesized section; print a list with 
labelit.stats_index"
  plot_section = None
    .type = str
    .help = "Miller indices of the section to be synthesized, comma separated, 
no spaces, such as H,0,L"
  image_range = None
    .type = ints(size=2)
    .help = "Range of data frames (inclusive) to be used for synthesized image, 
i.e., min frame no.,max frame no., no spaces"
  intensity_full_scale = 255
    .type = int
    .help = "Image intensity to be used as full scale (black)"
  pdf_output {
    file = None
      .type = str
      .help = "File name for pdf output"
  }
}
""")


from scitbx import matrix
from scitbx.array_family import flex
from cctbx.crystal_orientation import crystal_orientation
from cctbx.uctbx import unit_cell
from spotfinder.diffraction.imagefiles import 
Spotspickle_argument_module,image_files
from labelit.dptbx import AutoIndexEngine, Parameters
from labelit.command_line.imagefiles import QuickImage
from annlib_ext import AnnAdaptor

def get_precession_parameters(sources=[]):
  parameters = precession_master_phil.fetch(sources=sources)
  #validation not done here
  return parameters

def ai_factory(inputpd):
    subpd = inputpd["best_integration"]
    ai = 
AutoIndexEngine(inputpd["endstation"],inputpd["recommended_grid_sampling"])
    P = Parameters(xbeam=float(inputpd["xbeam"]),ybeam=float(inputpd["ybeam"]),
             
distance=float(inputpd["distance"]),twotheta=float(inputpd["twotheta"]))
    ai.setBase(P)
    ai.setWavelength(float(inputpd['wavelength']))
    ai.setMaxcell(float(inputpd['ref_maxcel']))
    ai.setDeltaphi(float(inputpd['deltaphi'])*math.pi/180.)
    ai.setMosaicity(subpd["mosaicity"])
    ai.setOrientation(subpd["orient"])
    return ai

def get_col(n,sqr):
  return matrix.col((sqr[n],sqr[n+3],sqr[n+6]))

class calculate_miller:
  def __init__(self,plot_section,ori):
    labels = "HKL"
    hkl_list = plot_section.split(",")
    self.section_number = None
    for trial_plot_normal_index in [0,1,2]:
      try:
        self.section_number = int(hkl_list[trial_plot_normal_index])
        self.idx1 = (trial_plot_normal_index+1)%3
        assert hkl_list[self.idx1]==labels[self.idx1]
        self.idx2 = (trial_plot_normal_index+2)%3
        assert hkl_list[self.idx2]==labels[self.idx2]
        self.idx0 = (trial_plot_normal_index+3)%3

        break
      except:
        pass # one of three settings must succeed
    assert self.section_number!=None
    assert self.idx0!=None and self.idx1!=None and self.idx2!=None
    print self.idx0,self.idx1,self.idx2
    rmat = matrix.sqr(ori.reciprocal_matrix())
    self.unit_recip_basis1 = get_col(self.idx1,rmat).normalize() #like b*-hat
    self.unit_recip_basis2 = get_col(self.idx2,rmat).normalize() #like c*-hat
    self.a_hat_perp = 
self.unit_recip_basis1.cross(self.unit_recip_basis2).normalize()

    # normal to the plotted plane, like b*-hat x c*-hat
    self.c_hat_perp = self.a_hat_perp.cross(self.unit_recip_basis1)
    # second direction of plot, like a-hat-perp x b*-hat

    self.recip_basis1 = get_col(self.idx1,rmat)
    self.recip_basis2 = get_col(self.idx2,rmat)
    self.recip_basis3 = get_col(self.idx0,rmat)
    #reciprocal angle between recip_basis1 & recip_basis2
    angle = math.acos(self.unit_recip_basis1.dot(
            self.unit_recip_basis2))

    #re-expression matrix;  (f1.e1 f2.e1)
    #                       (f1.e2 f2.e2)
    self.reexpress = 
matrix.sqr((self.recip_basis1.length(),self.recip_basis2.length()*math.cos(angle),0.,
                          0.,                        
self.recip_basis2.length()*math.sin(angle),0.,
                          0.,0.,1.)
                     ).inverse()


  def set_dmax(self,dmax):
    self.dmax=dmax

class precession_plot:
  def HKL_from_xy(self,x,y):
    # assumes x,y are page coordinates, origin at top left, x down (slow), y 
left to right (fast)
    # reciprocal space starts in the middle of page, axis1 to the right, axis2 
up
    width = float(self.P.labelit_precession.pixel_width)/2.0
    coord1 = ((float(y) - width)/width)*(1./self.miller_calc.dmax)
    coord2 = ((-float(x) + width)/width)*(1./self.miller_calc.dmax)

    #plotting vector, represented in the orthonormal basis e = (b*-hat, 
c-hat-perp)
    r = matrix.col((coord1,coord2,0.0))
    #re-express in the crystal basis, f = (b*, c*)
    miller = self.miller_calc.reexpress * r

    miller3 = self.miller_calc.section_number
    hkl_list = [0.,0.,0.]
    hkl_list[self.miller_calc.idx0]=miller3
    #print hkl_list

    #hkl_zero = self.projection_onto_section_zero(hkl_list)

    hkl_list[self.miller_calc.idx1]=miller[0]
    hkl_list[self.miller_calc.idx2]=miller[1]

    #correct for the zero of this section
    hkl_list = matrix.col(hkl_list) - self.hkl_zero
    #print "hkl_list",hkl_list

    if x%50==0 and y%50==0:
      print "%6d%6d"%(x,y),"%5.1f %5.1f %5.1f"%tuple(hkl_list),
    return tuple(hkl_list)

  def projection_onto_section_zero(self,hkl):
    #compute this point, P, in orthonormal reciprocal coordinates
    P = matrix.sqr(self.rstbx_ori.reciprocal_matrix()) * matrix.col(hkl)

    # the plane normal
    N = self.miller_calc.a_hat_perp

     #projection of P onto the plane, given that a point on the plane O is 
0,0,0 (otherwise Q=P-((P-O).dot(N))*N)
    Q = P - (P.dot(N))*N
    # these are still orthonormal reciprocal coordinates.  Want to convert them 
back to Miller indices
    M = matrix.sqr(self.rstbx_ori.direct_matrix()) * Q
    return M

  def xy_from_00(self):
    width = float(self.P.labelit_precession.pixel_width)/2.0
    miller =[self.hkl_zero[self.miller_calc.idx1],
             self.hkl_zero[self.miller_calc.idx2],
             self.hkl_zero[self.miller_calc.idx0]]

    r = self.miller_calc.reexpress.inverse()*miller
    coord1 = r[0]
    coord2 = r[1]
    x = -width*(coord2*self.miller_calc.dmax - 1.)
    y = width * (coord1*self.miller_calc.dmax + 1.)
    return 
x/float(self.P.labelit_precession.pixel_width),y/float(self.P.labelit_precession.pixel_width)

  def get_labelit_index_parameters(self,P):
    self.P = P # program parameters
    H = pickle.load(open("LABELIT_possible"))
    counter = [i["counter"] for i in H]
    orient = [i["orient"] for i in H]
    setting_index = counter.index(self.P.labelit_precession.bravais_choice)
    self.rstbx_ori = orient[setting_index]
    #analyze the HKL section request
    self.miller_calc = 
calculate_miller(self.P.labelit_precession.plot_section,self.rstbx_ori)
    miller3 = self.miller_calc.section_number
    hkl_list = [0.,0.,0.]
    hkl_list[self.miller_calc.idx0]=miller3
    self.hkl_zero = self.projection_onto_section_zero(hkl_list)

    G = pickle.load(open("LABELIT_pickle"))

    w = float( G['wavelength'] )
    self.ai = ai_factory(G)

    self.ai.setOrientation(self.rstbx_ori)
    self.pixelsz = float(G["pixel_size"])
    template = G["file"][G["file"].keys()[0]]
    I = image_files(Spotspickle_argument_module(template))
    a_file = I.filenames.FN[0]
    self.template = os.path.join(a_file.cwd,a_file.template)
    self.wildcard_count = self.template.count("#")

    return self

  def construct_image_lookup(self):
    self.reverse_lookup = {}
    self.all_image_centers = flex.double()
    self.deltaphi = None
    for x in xrange(self.P.labelit_precession.image_range[0],
      self.P.labelit_precession.image_range[1]+1):
      a_file = self.template.replace("#"*self.wildcard_count, 
("%%0%sd"%self.wildcard_count)%x)
      Q = QuickImage(a_file)
      if self.deltaphi == None:  self.deltaphi = Q.deltaphi
      assert self.deltaphi == Q.deltaphi
      phivalue = (Q.osc_start + (Q.deltaphi/2.0))%360.0
      #print "image",x,"phi",phivalue
      self.reverse_lookup[phivalue]=x
      self.all_image_centers.append(phivalue)
    self.distance_tree = AnnAdaptor(self.all_image_centers,1)

  def imagefunc(self,deg):
    modular_deg = deg%360.
    self.distance_tree.query(flex.double([modular_deg]))
    if math.sqrt(self.distance_tree.distances[0]) > self.deltaphi/2.0: return 
None
    image_number = 
self.reverse_lookup.get(self.all_image_centers[self.distance_tree.nn[0]])
    return image_number

  def get_plot_values(self):
    param = self.P
    all_images={} # a very large memory sink.  Might need a more clever 
implementation later.
                  # relies on having all the images in memory at the same time.
    init_value = 235
    self.all_values = 
flex.int(param.labelit_precession.pixel_width**2,init_value)
    self.all_values.resize(flex.grid(param.labelit_precession.pixel_width,
                                     param.labelit_precession.pixel_width))
    scale_factor = 255./param.labelit_precession.intensity_full_scale
    uc = self.rstbx_ori.unit_cell()
    self.miller_calc.set_dmax(param.labelit_precession.resolution_outer)

    for x in xrange(param.labelit_precession.pixel_width):
      for y in xrange(param.labelit_precession.pixel_width):
        #print x,y
        H,K,L = self.HKL_from_xy(x,y)

        resolution = uc.d((int(H),int(K),int(L)))
        if x%50==0 and y%50==0:
          print "%6.1f"%resolution
        if resolution < param.labelit_precession.resolution_outer :
          continue

        for item in self.ai.predict_hkl((H,K,L),self.miller_calc.dmax):
          #this is a kludge!  if the HKL is recorded through the Ewald sphere 
twice,
          # only pick up the first time.
          deg  = item[2]*180./math.pi
          image_number = self.imagefunc(deg)
          if image_number == None: continue
          pixelx = int(item[0]/self.pixelsz)
          pixely = int(item[1]/self.pixelsz)

          if not all_images.has_key(image_number):
            filenm = self.template.replace("#"*self.wildcard_count, 
("%%0%sd"%self.wildcard_count)%image_number)
            Q = QuickImage(filenm)
            Q.read()
            all_images[image_number]=Q
          this_data = all_images[image_number].linearintdata
          pxl_value = this_data[pixelx,pixely]
          #print "%4d %4d %7.3f%7.3f%7.3f,%7.3f,%7.2f->%3d x%4d y%4d val %6d"%(
          #  x,y,H,K,L,resolution,deg,image_number,pixelx,pixely,pxl_value)


          plotted_value = int(pxl_value * scale_factor)
          if plotted_value >  255:
            plotted_value = 255
          if plotted_value <  0:
            plotted_value = 0

          self.all_values[x,y] = 255 - plotted_value
          break

from reportlab.pdfgen.canvas import Canvas
from reportlab.lib.pagesizes import letter
from reportlab.lib.units import inch,cm,mm

page_origin = (20.,190.)
boxedge = 500.

class Graph:

  def __init__(self,fileout):
    self.c = Canvas(fileout,pagesize=letter)

  def title(self,text):
    lines = text.split('\n')
    self.c.setFont('Helvetica',12)
    for x in xrange(len(lines)):
      self.c.drawString(2*cm,(26-0.5*x)*cm,lines[x])

  def image(self,pi):
    self.c.drawInlineImage(pi,page_origin[0],page_origin[1],
      width=boxedge,height=boxedge)
    self.c.setFillColorRGB(1,0,0)
  def dot(self,dc):
    
self.c.circle(page_origin[0]+(dc[1]*boxedge),page_origin[1]+(boxedge-dc[0]*boxedge),r=1.,stroke=0,fill=1)

  def __del__(self):
    self.c.save()

class GeneratePDF:
  def __init__(self,project):
    self.image_size = project.P.labelit_precession.pixel_width
    self.R = Graph(project.P.labelit_precession.pdf_output.file)
    self.data = project.all_values
    self.section = project.P.labelit_precession.plot_section
    self.project = project

  def make_image_plots_detail(self):
    import Image
    mode = "L" # black and white
    HWsizes = (self.image_size, self.image_size)
    pil_image = Image.new(mode,HWsizes)

    data = list(self.data)

    pil_image.putdata(data)

    uc = self.project.rstbx_ori.unit_cell()
    axis = ["a*","b*","c*"][self.project.miller_calc.idx1]
    axis2 = ["a*","b*","c*"][self.project.miller_calc.idx2]
    angle = math.acos(self.project.miller_calc.unit_recip_basis1.dot(
            self.project.miller_calc.unit_recip_basis2))*180./math.pi


    self.R.title("One reciprocal lattice plane, %s. Red spot is the 
%s"%(self.section,
    self.section.replace("H","0").replace("K","0").replace("L","0"))+"""
Unit cell: %s"""%(uc)+"""
%s points in the --> direction starting at the red spot"""%axis+"""
%s is in the plane at a %5.1f degree angle"""%(axis2,angle) )

    self.R.image(pil_image)
    dotcoords = self.project.xy_from_00()
    self.R.dot(dotcoords)

    self.R.c.showPage()
    return self

def run(args):
  if args==[]:
    print usage()
    return
  argument_interpreter = libtbx.phil.command_line.argument_interpreter(
    master_phil=precession_master_phil,home_scope="hidden_symmetry")
  parsed_arguments = []
  for arg in args:
    if arg.find("help")>=0:
      param_master = get_precession_parameters(sources=[])
      param_master.show(attributes_level=1)
      return
    else:
      try:
        a = argument_interpreter.process(arg=arg)
      except:
        print "Unknown file or keyword: %s"%arg
        print
        return
      else:
        parsed_arguments.append(a)
  param_master = get_precession_parameters(sources=parsed_arguments)
  param_master.show()
  param = param_master.extract()
  PP = precession_plot().get_labelit_index_parameters(param)
  PP.construct_image_lookup()
  PP.get_plot_values()
  PDF = GeneratePDF(PP)
  PDF.make_image_plots_detail()

if __name__=="__main__":
  import sys
  run(sys.argv[1:])

Reply via email to