aims 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -73,7 +73,7 @@ And here is how you get a (100) surface with 7 layers and 20 angstrom of vacuum
73
73
  And here is how you can constrain the bottom three layers
74
74
  constrain = 3
75
75
  puts zb.get_001_surface(layers, vacuum, constrain)
76
-
76
+
77
77
  == Scripts that come with the Aims GEM
78
78
 
79
79
  There are currently two scripts that come with the GEM
@@ -28,6 +28,10 @@ optParser = OptionParser.new do |opts|
28
28
  options[:debug] = true
29
29
  end
30
30
 
31
+ opts.on('-g', '--geometry', 'Output Geometry for selected relaxation steps') do
32
+ options[:geometry] = true
33
+ end
34
+
31
35
  opts.on('--geometry-delta', 'Display change from input geometry to final geometry') do
32
36
  options[:geometry_delta] = true
33
37
  end
@@ -59,7 +63,7 @@ begin
59
63
  }
60
64
 
61
65
  int_format = "%-20s %20i"
62
- float_format = "%-20s %20.5f"
66
+ float_format = "%-20s 20.5f"
63
67
  exp_format = "%-20s %20.5e"
64
68
 
65
69
  sciter_format = "%-20s %20i"
@@ -144,6 +148,10 @@ begin
144
148
  }
145
149
  end
146
150
 
151
+ if options[:geometry]
152
+ puts step.geometry.format_geometry_in
153
+ end
154
+
147
155
  puts "\n\n"
148
156
 
149
157
 
@@ -161,6 +169,8 @@ begin
161
169
  output.computational_steps.each{|cs|
162
170
  puts int_format % [cs[:description], cs[:value]]
163
171
  }
172
+
173
+
164
174
  if options[:timings]
165
175
  output.timings.each{|t| puts " " +timings_format % [t[:description], t[:cpu_time]]}
166
176
  end
@@ -29,6 +29,7 @@ require 'aims/geometry.rb'
29
29
  require 'aims/volume.rb'
30
30
  require 'aims/wurtzite.rb'
31
31
  require 'aims/zinc_blende.rb'
32
+ require 'aims/kd_tree.rb'
32
33
 
33
34
  # {include:file:README.rdoc}
34
35
  module Aims
@@ -14,7 +14,9 @@ module Aims
14
14
  end
15
15
  end
16
16
 
17
+ #
17
18
  class Gallium < Geometry
19
+
18
20
  def initialize(a, b, c, u, v)
19
21
  v1 = Vector[a/2.0, -b/2.0, 0]
20
22
  v2 = Vector[a/2.0, b/2.0, 0]
@@ -23,8 +23,6 @@ module Aims
23
23
  # A three element array of lattice vectors for periodic systems
24
24
  attr_accessor :lattice_vectors
25
25
 
26
- # An array of Aims::Bond objects calculated when the Geometry is defined.
27
- attr_accessor :bonds
28
26
 
29
27
  # clip_planes is an array of planes
30
28
  # The planes are defined with respect to the vectors millerX and millerZ
@@ -107,30 +105,91 @@ module Aims
107
105
  end
108
106
  end
109
107
 
108
+ # Return the
109
+ def bonds(visibility = :visibleOnly)
110
+ if (visibility == :visibleOnly) and (0 < @clip_planes.size)
111
+ @visibleBonds
112
+ else
113
+ @bonds
114
+ end
115
+ end
116
+
117
+ # Remove the atoms satisfying the criteria specified in block
118
+ def remove_atoms
119
+ @atoms.reject!{|a|
120
+ yield a
121
+ }
122
+ recache_visible_atoms
123
+ self
124
+ end
125
+
110
126
  # Generate and cache bonds for this geometry.
111
127
  # A bond will be generated for every pair of atoms closer than +bond_length+
112
- def make_bonds(bond_length = 4.0)
128
+ def make_bonds(bond_length = 3.0)
113
129
  # initialize an empty array
114
- self.bonds = Array.new
130
+ @bonds = Array.new
115
131
 
116
132
  # Make bonds between all atoms
117
- stack = atoms.dup
133
+ # stack = atoms.dup
134
+ atoms_extended = atoms.dup
135
+ if periodic?
136
+ v1 = lattice_vectors[0]
137
+ v2 = lattice_vectors[1]
138
+ atoms.each{|a|
139
+ [-1, 0, 1].each{|n1|
140
+ [-1, 0, 1].each{|n2|
141
+ atoms_extended << a.displace(n1*v1[0] + n2*v2[0], n1*v1[1] + n2*v2[1], n1*v1[2] + n2*v2[2])
142
+ }
143
+ }
144
+ }
145
+ end
146
+
147
+ tree = KDTree.new(atoms_extended, 3)
148
+ atoms.each{|a|
149
+ r = 4
150
+ neighbors = tree.find([a.x-r, a.x+r], [a.y-r, a.y+r], [a.z-r, a.z+r])
151
+ neighbors.each{|n|
152
+ b = Bond.new(a, n)
153
+ @bonds << b if b.length < bond_length
154
+ }
155
+ }
118
156
 
119
- atom1 = stack.pop
120
- while (not stack.empty?)
121
- stack.each{|atom2|
122
- b = Bond.new(atom1, atom2)
123
- self.bonds << b if b.length < bond_length
124
- }
125
- atom1 = stack.pop
126
- end
157
+ # atom1 = stack.pop
158
+ # while (not stack.empty?)
159
+ # stack.each{|atom2|
160
+ # b = Bond.new(atom1, atom2)
161
+ # @bonds << b if b.length < bond_length
162
+ # if periodic?
163
+ # v1 = lattice_vectors[0]
164
+ # v2 = lattice_vectors[1]
165
+ # [-1, 0, 1].each{|n1|
166
+ # [-1, 0, 1].each{|n2|
167
+ # b = Bond.new(atom1, atom2.displace(n1*v1[0] + n2*v2[0], n1*v1[1] + n2*v2[1], n1*v1[2] + n2*v2[2]))
168
+ # @bonds << b if b.length < bond_length
169
+ # }
170
+ # }
171
+ # end
172
+ # }
173
+ # atom1 = stack.pop
174
+ # end
127
175
  end
128
176
 
177
+ # Return true if this geometry has lattice vectors defined
178
+ # and is periodic in R3
179
+ def periodic?
180
+ if lattice_vectors and lattice_vectors.size == 3
181
+ return true
182
+ else
183
+ return false
184
+ end
185
+ end
186
+
129
187
  # Add a clip Plane to the unit cell
130
188
  # recache the visible atoms if called with +recache = true+ (the Default)
131
189
  def add_plane(aPlane, recache = true)
132
190
  self.clip_planes << aPlane
133
191
  recache_visible_atoms if recache
192
+ aPlane
134
193
  end
135
194
 
136
195
  # Add a clipping plane defined by the outward normal (h,k,l)
@@ -255,7 +314,26 @@ module Aims
255
314
  @visibleAtoms << a if i == 0
256
315
  }
257
316
 
258
- make_bonds if makeBonds
317
+ if @visibleBonds
318
+ @visibleBonds.clear
319
+ else
320
+ @visibleBonds = []
321
+ end
322
+
323
+ make_bonds if (makeBonds or @bonds.nil?)
324
+
325
+ @bonds.each{|b|
326
+ a0 = b[0]
327
+ a1 = b[1]
328
+ i0 = plane_count
329
+ i1 = plane_count
330
+ @clip_planes.each{|p|
331
+ i0 = i0-1 if 0 >= p.distance_to_point(a0.x, a0.y, a0.z)
332
+ i1 = i1-1 if 0 >= p.distance_to_point(a1.x, a1.y, a1.z)
333
+ }
334
+ @visibleBonds << b if (i0 + i1) < 2
335
+ }
336
+
259
337
  end
260
338
 
261
339
  # Rotate the geometry in 3 dimensions. The rotation is
@@ -283,9 +361,10 @@ module Aims
283
361
  mat*v
284
362
  }
285
363
  uc = Geometry.new(newatoms, newvectors)
286
- uc.cart_to_miller = mat*self.cart_to_miller
287
- uc.miller_to_cart = uc.cart_to_miller.inverse
288
-
364
+ if self.cart_to_miller
365
+ uc.cart_to_miller = mat*self.cart_to_miller
366
+ uc.miller_to_cart = uc.cart_to_miller.inverse
367
+ end
289
368
  return uc
290
369
  end
291
370
 
@@ -364,7 +443,7 @@ module Aims
364
443
 
365
444
  # Remove the specified atom from the unit cell
366
445
  def remove_atom(atom)
367
- atoms.reject!{|a|
446
+ atoms(:all).reject!{|a|
368
447
  a.id == atom.id
369
448
  }
370
449
  # Force a rehash of nearest-neighbor tree
@@ -416,7 +495,7 @@ module Aims
416
495
  u.lattice_vectors = [Vector[nx.abs*v1[0], nx.abs*v1[1], nx.abs*v1[2]],
417
496
  Vector[ny.abs*v2[0], ny.abs*v2[1], ny.abs*v2[2]],
418
497
  Vector[nz.abs*v3[0], nz.abs*v3[1], nz.abs*v3[2]]]
419
- u.make_bonds
498
+ # u.make_bonds
420
499
  return u
421
500
  end
422
501
 
@@ -424,7 +503,7 @@ module Aims
424
503
  # Currently does no validation on lattice vectors on miller vectors
425
504
  def <<(aGeometry)
426
505
  self.atoms.concat(aGeometry.atoms)
427
- self.make_bonds
506
+ # self.make_bonds
428
507
  return self
429
508
  end
430
509
 
@@ -446,9 +525,9 @@ module Aims
446
525
  end
447
526
 
448
527
  # return a string in xyz format
449
- def format_xyz
528
+ def format_xyz(title = "Aims Geoemtry")
450
529
  output = self.atoms.size.to_s + "\n"
451
- output << "Aims Geometry \n"
530
+ output << "#{title} \n"
452
531
  self.atoms.each{ |a|
453
532
  output << [a.species, a.x.to_s, a.y.to_s, a.z.to_s].join("\t") + "\n"
454
533
  }
@@ -478,7 +557,7 @@ module Aims
478
557
 
479
558
  # Move all atoms inside the primitive volume defined by the
480
559
  # six planes of the lattice vectors
481
- def correct
560
+ def correct(repeat_border_atoms = false)
482
561
 
483
562
  # Hash for storing bounding planes and the out-of-plane vector
484
563
  # by which each atom will be displaced to move it into the primitive volume
@@ -519,25 +598,58 @@ module Aims
519
598
  # Make a coyp of the unit cell
520
599
  new_unit_cell = self.copy
521
600
 
601
+ # atoms on the border will be repeated with
602
+ # periodicity of lattice vectors for better rendering
603
+ border_atoms = {}
604
+
522
605
  # Move each atom behind all the planes
523
- new_unit_cell.atoms(false).each do |atom|
606
+ new_unit_cell.atoms(false).each_with_index do |atom, i|
524
607
  planes_vecs.each_pair do |p, v|
525
608
  if p.distance_to_point(0,0,0) == 0
526
609
  # If the plane intersects the origin then
527
610
  # move atoms not on the plane (inequality)
528
- while p.distance_to_point(atom.x, atom.y, atom.z) > 0
611
+ while p.distance_to_point(atom.x, atom.y, atom.z) > 1e-4
529
612
  atom.displace!(v[0], v[1], v[2])
530
613
  end
531
614
  else
532
615
  # Move atoms that lie on the plane if the plane doesn't intersect the origin
533
- while p.distance_to_point(atom.x, atom.y, atom.z) >= 0
616
+ while p.distance_to_point(atom.x, atom.y, atom.z) >= -1e-4
534
617
  atom.displace!(v[0], v[1], v[2])
535
618
  end
536
619
  end
620
+
621
+ # This part repeats atoms on the unit cell boundaries
622
+ # useful for drawing pictures, but these atoms are really repeats
623
+ # Add each border that intersects the atom to a list
624
+ if p.distance_to_point(atom.x, atom.y, atom.z) == 0
625
+ if border_atoms[atom]
626
+ border_atoms[atom] << v
627
+ else
628
+ border_atoms[atom] = [v]
629
+ end
630
+ end
537
631
  end
538
632
  end
633
+
634
+
635
+
636
+ # Add more border atoms for each combination of lattice planes
637
+ if repeat_border_atoms
638
+ border_atoms.each_pair{|atom, planes|
639
+ planes.size.times{|i|
640
+ combos = Volume.choose(planes, i+1)
641
+ combos.each{|combo|
642
+ x = combo.inject(0){|sum, v| sum = sum + v[0]}
643
+ y = combo.inject(0){|sum, v| sum = sum + v[1]}
644
+ z = combo.inject(0){|sum, v| sum = sum + v[2]}
645
+ puts [x,y,z]
646
+ new_unit_cell.atoms(:allAtoms) << atom.displace(x, y, z)
647
+ }
648
+ }
649
+ }
650
+ end
539
651
  new_unit_cell.atoms.uniq!
540
- new_unit_cell.make_bonds
652
+ # new_unit_cell.make_bonds
541
653
  return new_unit_cell
542
654
 
543
655
  end
@@ -3,17 +3,7 @@ module Aims
3
3
 
4
4
  # Utility class for parsing an Aims geometry file
5
5
  # Example Usage:
6
- # geom = Aims::GeometryParser.parse("geometry.in")
7
- #
8
- # # Constrain atoms below some z value
9
- # geom.each{|atom|
10
- # if (atom.z < someValue)
11
- # atom.constrain = true
12
- # end
13
- # }
14
- # File.open("new_geometry.in", "w") do |f|
15
- # f.puts geom.format_geometry_in
16
- # end
6
+ # uc = Aims::GeometryParser.parse("geometry.in")
17
7
  class GeometryParser
18
8
 
19
9
  # Parse a String representation of a geometry.in file
@@ -46,7 +36,7 @@ module Aims
46
36
  atoms.last.constrain << c
47
37
  end
48
38
  }
49
- Geometry.new(atoms, vectors)
39
+ Geometry.new(atoms, vectors, false)
50
40
  end
51
41
 
52
42
  # Parse a geometry.in file
@@ -0,0 +1,94 @@
1
+ module Aims
2
+ # Courtesy of https://gist.github.com/cbrumelle/328423
3
+ class KDTree
4
+ attr_reader :root
5
+ attr_reader :points
6
+
7
+ def initialize(points, dim)
8
+ @dim = dim
9
+ @root = KDNode.new(dim).parse(points)
10
+ end
11
+
12
+ def add_node(point)
13
+ @root.add(point)
14
+ end
15
+
16
+ def find(*range)
17
+ range.collect!{ |pa|
18
+ pa = Range.new(pa.first, pa.last) if pa.kind_of? Array
19
+ }
20
+ @points = []
21
+ query(range, @root)
22
+ @points
23
+ end
24
+
25
+ def query(range, node)
26
+ axis = node.axis
27
+ median = node.location[axis]
28
+
29
+ if node.left && (median >= range[axis].begin)
30
+ query(range, node.left); # /* Skip left if max of left tree (median) is out of range */
31
+ end
32
+ if node.right && (median <= range[axis].end)
33
+ query(range, node.right); # /* Skip right if min of right tree (median) is out of range */
34
+ end
35
+ if (0..@dim-1).all?{|ax|
36
+ range[ax].include? node.location[ax]
37
+ }
38
+ @points << node.location;
39
+ end
40
+ end
41
+
42
+ def print
43
+ @root.print
44
+ end
45
+ end
46
+
47
+ class KDNode
48
+ attr_reader :left, :right
49
+ attr_reader :location
50
+
51
+ attr_reader :axis
52
+
53
+ def initialize(dim, location=nil, left=nil, right=nil)
54
+ @dim = dim
55
+ @location = location
56
+ @left = left
57
+ @right = right
58
+ end
59
+
60
+ def parse(points, depth = 0)
61
+ @axis = depth % @dim
62
+
63
+ points = points.sort_by{|point| point[@axis]}
64
+ half = points.length / 2
65
+
66
+ @location = points[half]
67
+ @left = KDNode.new(@dim).parse(points[0..half-1], depth+1) unless half < 1
68
+ @right = KDNode.new(@dim).parse(points[half+1..-1], depth+1) unless half+1 >= points.length
69
+ self
70
+ end
71
+
72
+ def add(point)
73
+ if @location[@axis] < point[@axis]
74
+ @left ? @left.add(point) : @left = KDNode.new(point)
75
+ else
76
+ @right ? @right.add(point) : @right = KDNode.new(point)
77
+ end
78
+ end
79
+
80
+ def remove
81
+ self.parse(@left.to_a + @right.to_a, @axis)
82
+ end
83
+
84
+ def to_a
85
+ @left.to_a + [@location] + @right.to_a
86
+ end
87
+
88
+ def print(l=0)
89
+ @left.print(l+1) if @left
90
+ puts(" "*l + @location.inspect)
91
+ @right.print(l+1) if @right
92
+ end
93
+ end
94
+ end
@@ -208,6 +208,7 @@ module Aims
208
208
  class AimsOutput
209
209
  # Each Aims::GeometryStep geometry relaxation step
210
210
  attr_accessor :geometry_steps
211
+ alias_method :relaxation_steps, :geometry_steps
211
212
 
212
213
  # The k-point grid for periodic calculations
213
214
  attr_accessor :k_grid
@@ -246,7 +247,7 @@ module Aims
246
247
  end
247
248
 
248
249
  def final_geometry
249
- self.geometry_steps.last.geometry
250
+ self.geometry_steps.last.geometry
250
251
  end
251
252
 
252
253
  def final_step
@@ -397,6 +398,7 @@ module Aims
397
398
  retval.original_file = filename
398
399
 
399
400
  File.open(filename, 'r') do |f|
401
+ counter = 0
400
402
  f.each_line{|line|
401
403
  case line
402
404
  when /Found k-point grid:/
@@ -459,8 +461,9 @@ module Aims
459
461
  retval.geometry_steps << GeometryStep.new
460
462
  retval.geometry_step.step_num = last_step_num + 1
461
463
  retval.geometry_step.geometry = OutputParser.parse_updated_geometry(f, n_atoms)
462
- # retval.geometry_step.geometry.lattice_vectors = vectors
463
-
464
+ unless retval.geometry_step.geometry.lattice_vectors
465
+ retval.geometry_step.geometry.lattice_vectors = vectors
466
+ end
464
467
  when /\ Final\ atomic\ structure\:/
465
468
  retval.geometry_step.geometry = OutputParser.parse_updated_geometry(f, n_atoms)
466
469
  # retval.geometry_step.geometry.lattice_vectors = vectors
@@ -476,7 +479,6 @@ module Aims
476
479
  end
477
480
  }
478
481
  end
479
-
480
482
  return retval
481
483
 
482
484
  end
@@ -9,6 +9,8 @@ module Aims
9
9
  class Plane
10
10
  attr_reader :a, :b, :c, :d
11
11
 
12
+ include Vectorize
13
+
12
14
  # Initialize this plane with the normal (a,b,c) and a
13
15
  # point (x,y,z) on the plane
14
16
  def initialize(a, b, c, x=0, y=0, z=0)
@@ -53,10 +55,35 @@ module Aims
53
55
  v*(1/v.r)
54
56
  end
55
57
 
56
- # The equation for the interstion of a ray and a plane
57
- # NOT YET IMPLEMENTED
58
+ # The equation for the interstion of ray defined by r(t) = (a + b*t)
59
+ # [a, b] are vectors where a is the tail of the ray and b points in the direction of the ray and t > 0
60
+ # and the plane normal Pn = [A B C]
61
+ #
62
+ # Substituting r(t) into the equation of the plane gives:
63
+ # A(ax + bx*t) + B(ay + by*t) + C(az + bz*t) + D = 0
64
+ #
65
+ # Solve for t
66
+ # t = (Pn dot a + D)/(Pn dot b) = V0 / Vd
67
+ # if:
68
+ # Vd = 0, then no intersection
69
+ # t < 0, then intersection behind ray origin
70
+ #
71
+ # Find point of intersection
72
+ # [(ax + bx*t) (ay + by*t) (az + bz*t)]
58
73
  def intersection_with_ray(a, b)
59
- raise "Sorry. Plane#intersection_with_ray is not yet implemented"
74
+ n = self.unit_normal
75
+ vd = dot(n, b)
76
+ if vd == 0
77
+ return nil
78
+ else
79
+ v0 = dot(n, a) + @d
80
+ t = -v0/vd
81
+ if t < 0
82
+ return nil
83
+ else
84
+ return a + b*t
85
+ end
86
+ end
60
87
  end
61
88
 
62
89
  # Displace this plane a distance in the direction of its normal
@@ -20,10 +20,8 @@ module Aims
20
20
 
21
21
  def get_bulk
22
22
  # The lattice constant
23
- a = (ARGV[0] || 4.0).to_f
23
+ a = lattice_const
24
24
  c = 1.63299*a # sqrt(8/3)a
25
- #a = 6.19231 # Strained GaSb, Unstrained GaSb is 6.22
26
- #a = 5.75 # Unstrained GaAs
27
25
 
28
26
  # The atoms on a HCP
29
27
  as1 = Atom.new(0,0,0,'As')
@@ -46,45 +46,43 @@ module Aims
46
46
  end
47
47
 
48
48
  # Fill the given volume with atoms
49
- # This method is still under development. It is removed for the 0.2.0 release
50
- #
51
- # def fill_volume(volume)
52
- #
53
- # # First fill a cube that bounds the volume
54
- # max = volume.max_point
55
- # min = volume.min_point
56
- #
57
- # dx = max[0] - min[0]
58
- # dy = max[1] - min[1]
59
- # dz = max[2] - min[2]
60
- #
61
- # bulk = get_bulk
62
- #
63
- # # This inverse matrix gives the number of repetitions
64
- # m = Matrix[[dx,0,0], [0,dy,0], [0,0,dz]]
65
- # v = Matrix[bulk.lattice_vectors[0].to_a,
66
- # bulk.lattice_vectors[1].to_a,
67
- # bulk.lattice_vectors[2].to_a]
68
- # rep_mat = m*(v.inverse)
69
- #
70
- # # The only way I can figure out how to do this for an
71
- # # arbitrary set of lattice vectors is to fill the volume
72
- # # out along each edge of the super-cube and then eliminate duplicates
73
- # atoms = []
74
- # 3.times do |i|
75
- # # this vector is the number of repetitions in the unit cell
76
- # # to fill the volume out along the i-th edge of the super-cube
77
- # n_repeat = rep_mat.row(i)
78
- #
79
- # # Give the proper sign to the repeat
80
- # nx = (n_repeat[0] < 0) ? n_repeat[0].floor-1 : n_repeat[0].ceil+1
81
- # ny = (n_repeat[1] < 0) ? n_repeat[1].floor-1 : n_repeat[1].ceil+1
82
- # nz = (n_repeat[2] < 0) ? n_repeat[2].floor-1 : n_repeat[2].ceil+1
83
- #
84
- # atoms += bulk.repeat(nx, ny, nz).atoms.find_all{|a| volume.contains_point(a.x, a.y, a.z)}
85
- # end
86
- # Geometry.new(atoms.uniq)
87
- # end
49
+ def fill_volume(volume)
50
+
51
+ # First fill a cube that bounds the volume
52
+ max = volume.max_point
53
+ min = volume.min_point
54
+
55
+ dx = max[0] - min[0]
56
+ dy = max[1] - min[1]
57
+ dz = max[2] - min[2]
58
+
59
+ bulk = get_bulk
60
+
61
+ # This inverse matrix gives the number of repetitions
62
+ m = Matrix[[dx,0,0], [0,dy,0], [0,0,dz]]
63
+ v = Matrix[bulk.lattice_vectors[0].to_a,
64
+ bulk.lattice_vectors[1].to_a,
65
+ bulk.lattice_vectors[2].to_a]
66
+ rep_mat = m*(v.inverse)
67
+
68
+ # The only way I can figure out how to do this for an
69
+ # arbitrary set of lattice vectors is to fill the volume
70
+ # out along each edge of the super-cube and then eliminate duplicates
71
+ atoms = []
72
+ 3.times do |i|
73
+ # this vector is the number of repetitions in the unit cell
74
+ # to fill the volume out along the i-th edge of the super-cube
75
+ n_repeat = rep_mat.row(i)
76
+
77
+ # Give the proper sign to the repeat
78
+ nx = (n_repeat[0] < 0) ? n_repeat[0].floor-1 : n_repeat[0].ceil+1
79
+ ny = (n_repeat[1] < 0) ? n_repeat[1].floor-1 : n_repeat[1].ceil+1
80
+ nz = (n_repeat[2] < 0) ? n_repeat[2].floor-1 : n_repeat[2].ceil+1
81
+
82
+ atoms += bulk.repeat(nx, ny, nz).atoms.find_all{|a| volume.contains_point(a.x, a.y, a.z)}
83
+ end
84
+ Geometry.new(atoms.uniq)
85
+ end
88
86
 
89
87
  # Return a unit cell for a slab of 001
90
88
  # Specify the number of atomic monolayers,
@@ -0,0 +1,35 @@
1
+ require 'aims'
2
+ include Aims
3
+
4
+ describe Plane do
5
+ p = Plane.new(0,0,1,0)
6
+
7
+ it "should intersect the ray +z at (0 0 0)" do
8
+ a = Vector[0,0,0]
9
+ b = Vector[0,0,1]
10
+ x = p.intersection_with_ray(a, b)
11
+ x.should eq(a)
12
+ end
13
+
14
+ it "should intersect the ray +z with origin (0,0,-1) at (0 0 0)" do
15
+ a = Vector[0,0,-1]
16
+ b = Vector[0,0,1]
17
+ x = p.intersection_with_ray(a, b)
18
+ x.should eq(Vector[0,0,0])
19
+ end
20
+
21
+ it "should not intersect the ray +x" do
22
+ a = Vector[0,0,0]
23
+ b = Vector[1,0,0]
24
+ x = p.intersection_with_ray(a,b)
25
+ x.should be_nil
26
+ end
27
+
28
+ it "should not intersect the +z ray with origin (0,0,1)" do
29
+ a = Vector[0,0,1]
30
+ b = Vector[0,0,1]
31
+ x = p.intersection_with_ray(a,b)
32
+ x.should be_nil
33
+ end
34
+
35
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aims
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-01 00:00:00.000000000Z
12
+ date: 2013-05-22 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &3864410 !ruby/object:Gem::Requirement
16
+ requirement: &5425000 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *3864410
24
+ version_requirements: *5425000
25
25
  description: Support for generation and parsing of input and output files for FHI-AIMS
26
26
  DFT package
27
27
  email: joshua.shapiro@gmail.com
@@ -38,6 +38,7 @@ files:
38
38
  - lib/aims/cube.rb
39
39
  - lib/aims/geometry.rb
40
40
  - lib/aims/geometry_parser.rb
41
+ - lib/aims/kd_tree.rb
41
42
  - lib/aims/output.rb
42
43
  - lib/aims/plane.rb
43
44
  - lib/aims/Tetragonal.rb
@@ -50,6 +51,7 @@ files:
50
51
  - spec/atom_spec.rb
51
52
  - spec/bond_spec.rb
52
53
  - spec/output_spec.rb
54
+ - spec/plane_spec.rb
53
55
  - spec/zinc_blende_spec.rb
54
56
  homepage: https://github.com/jns/Aims
55
57
  licenses: []
@@ -80,5 +82,6 @@ test_files:
80
82
  - spec/atom_spec.rb
81
83
  - spec/bond_spec.rb
82
84
  - spec/output_spec.rb
85
+ - spec/plane_spec.rb
83
86
  - spec/zinc_blende_spec.rb
84
87
  has_rdoc: