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.
- 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:
|