aims 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +1 -1
- data/bin/aims_output.rb +11 -1
- data/lib/aims.rb +1 -0
- data/lib/aims/Tetragonal.rb +2 -0
- data/lib/aims/geometry.rb +139 -27
- data/lib/aims/geometry_parser.rb +2 -12
- data/lib/aims/kd_tree.rb +94 -0
- data/lib/aims/output.rb +6 -4
- data/lib/aims/plane.rb +30 -3
- data/lib/aims/wurtzite.rb +1 -3
- data/lib/aims/zinc_blende.rb +37 -39
- data/spec/plane_spec.rb +35 -0
- metadata +7 -4
data/README.rdoc
CHANGED
@@ -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
|
data/bin/aims_output.rb
CHANGED
@@ -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
|
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
|
data/lib/aims.rb
CHANGED
data/lib/aims/Tetragonal.rb
CHANGED
data/lib/aims/geometry.rb
CHANGED
@@ -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 =
|
128
|
+
def make_bonds(bond_length = 3.0)
|
113
129
|
# initialize an empty array
|
114
|
-
|
130
|
+
@bonds = Array.new
|
115
131
|
|
116
132
|
# Make bonds between all atoms
|
117
|
-
|
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
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
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
|
-
|
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
|
-
|
287
|
-
|
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
|
-
|
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 << "
|
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).
|
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) >
|
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) >=
|
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
|
data/lib/aims/geometry_parser.rb
CHANGED
@@ -3,17 +3,7 @@ module Aims
|
|
3
3
|
|
4
4
|
# Utility class for parsing an Aims geometry file
|
5
5
|
# Example Usage:
|
6
|
-
#
|
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
|
data/lib/aims/kd_tree.rb
ADDED
@@ -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
|
data/lib/aims/output.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
data/lib/aims/plane.rb
CHANGED
@@ -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
|
57
|
-
#
|
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
|
-
|
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
|
data/lib/aims/wurtzite.rb
CHANGED
@@ -20,10 +20,8 @@ module Aims
|
|
20
20
|
|
21
21
|
def get_bulk
|
22
22
|
# The lattice constant
|
23
|
-
a =
|
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')
|
data/lib/aims/zinc_blende.rb
CHANGED
@@ -46,45 +46,43 @@ module Aims
|
|
46
46
|
end
|
47
47
|
|
48
48
|
# Fill the given volume with atoms
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
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,
|
data/spec/plane_spec.rb
ADDED
@@ -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.
|
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:
|
12
|
+
date: 2013-05-22 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
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: *
|
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:
|