aims 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: