aims 0.2.0 → 0.2.1

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
@@ -55,9 +55,18 @@ begin
55
55
  exit
56
56
  end
57
57
  outputs = files.collect{|f|
58
- Aims::OutputParser.parse(f)
58
+ Aims::OutputParser.parse(f)
59
59
  }
60
60
 
61
+ int_format = "%-20s %20i"
62
+ float_format = "%-20s %20.5f"
63
+ exp_format = "%-20s %20.5e"
64
+
65
+ sciter_format = "%-20s %20i"
66
+ timings_format = "%-35s %20.5f"
67
+ energy_format = "%-35s %20.5f"
68
+ force_format = "%-35s %20.5e"
69
+
61
70
  total_sc_iterations = 0
62
71
  total_relaxations = 0
63
72
 
@@ -91,11 +100,6 @@ begin
91
100
 
92
101
  total_relaxations += 1
93
102
  total_sc_iterations += step.sc_iterations.size
94
-
95
- sciter_format = "%-20s %20i"
96
- timings_format = "%-35s %20.5f"
97
- energy_format = "%-35s %20.5f"
98
- force_format = "%-35s %20.5e"
99
103
 
100
104
  puts "= Relaxation Step #{step.step_num} ="
101
105
 
@@ -122,9 +126,9 @@ begin
122
126
  puts " == SC Iteration #{iter} =="
123
127
 
124
128
  # Output convergence criterion
125
- puts indent + energy_format % ["Change in total energy", sc_iter.d_etot]
126
- puts indent + energy_format % ["Change in sum of eigenvalues", sc_iter.d_eev]
127
- puts indent + energy_format % ["Change in charge density", sc_iter.d_rho]
129
+ puts indent + exp_format % ["Change in total energy", sc_iter.d_etot]
130
+ puts indent + exp_format % ["Change in sum of eigenvalues", sc_iter.d_eev]
131
+ puts indent + exp_format % ["Change in charge density", sc_iter.d_rho]
128
132
 
129
133
  # Output timings if requested
130
134
  if options[:timings]
@@ -145,10 +149,23 @@ begin
145
149
 
146
150
  }
147
151
 
152
+ puts "= Calculation Summary ="
148
153
  unless output.geometry_converged
149
154
  puts "Warning Geometry not converged!"
150
155
  end
151
156
 
157
+ puts int_format % ["Number of SC Iterations found:", total_sc_iterations]
158
+ puts int_format % ["Number of Relaxation Steps found:", total_relaxations]
159
+ puts float_format % ["Total CPU time", output.total_cpu_time]
160
+
161
+ output.computational_steps.each{|cs|
162
+ puts int_format % [cs[:description], cs[:value]]
163
+ }
164
+ if options[:timings]
165
+ output.timings.each{|t| puts " " +timings_format % [t[:description], t[:cpu_time]]}
166
+ end
167
+ # puts timings_format % ["Total Wall time", output.total_wall_time]
168
+
152
169
  if options[:geometry_delta]
153
170
  puts "= Change in atomic positions for calculation"
154
171
  puts output.geometry_steps.last.geometry.delta(output.geometry_steps.first.geometry)
@@ -8,13 +8,13 @@ if files.empty?
8
8
  end
9
9
 
10
10
  STDOUT.sync = true
11
- puts "%-10s \t %-20s \t %-15s \t %9s \t %7s \t %10s \t %12s \t %8s \t %10s" % %w(RUN FILE TOTAL_ENERGY NUM_ATOMS K-GRID CONVERGED RELAX_STEPS SC_ITERS TOTAL_TIME)
12
- format = "%-10s \t %-20s \t %+15e \t %9i \t %7s \t %10s \t %12i \t %8i \t %10.2f"
11
+ puts "%-40s \t %-15s \t %9s \t %7s \t %10s \t %12s \t %8s \t %10s" % %w(FILE TOTAL_ENERGY NUM_ATOMS K-GRID CONVERGED RELAX_STEPS SC_ITERS TOTAL_TIME)
12
+ format = "%-40s \t %+15f \t %9i \t %7s \t %10s \t %12i \t %8i \t %10.2f"
13
13
  files.each{|f|
14
14
  run = f.split(".").last
15
15
  begin
16
16
  o = Aims::OutputParser.parse(f)
17
- puts format % [run, f[0...20],
17
+ puts format % [f[0...40],
18
18
  (o.total_energy.nan? ? Float::NAN : o.total_energy),
19
19
  (o.n_atoms or -1),
20
20
  (o.k_grid ? o.k_grid.squeeze : "-"),
@@ -30,6 +30,7 @@ require 'aims/volume.rb'
30
30
  require 'aims/wurtzite.rb'
31
31
  require 'aims/zinc_blende.rb'
32
32
 
33
- # :include:README.rdoc
33
+ # {include:file:README.rdoc}
34
34
  module Aims
35
+ include Math
35
36
  end
@@ -0,0 +1,31 @@
1
+ module Aims
2
+ # A factory class for generating tetragonal geometries
3
+ class Tetragonal < Geometry
4
+
5
+ # @param species [String] The atomic species
6
+ # @param a [Float] The length of the a vector
7
+ # @param c [Float] The length of the c vector
8
+ def initialize(species, a, c)
9
+ a = Atom.new(0,0,0,species)
10
+ v1 = Vector[a, 0, 0]
11
+ v2 = Vector[0, a, 0]
12
+ v3 = Vector[a/2.0, a/2.0, c/2.0]
13
+ super(a, [v1, v2, v3])
14
+ end
15
+ end
16
+
17
+ class Gallium < Geometry
18
+ def initialize(a, b, c, u, v)
19
+ v1 = Vector[a/2.0, -b/2.0, 0]
20
+ v2 = Vector[a/2.0, b/2.0, 0]
21
+ v3 = Vector[0, 0, c]
22
+
23
+ atoms = [Atom.new(0, u*b, v*c, "Ga"),
24
+ Atom.new(0, -u*b, -v*c, "Ga"),
25
+ Atom.new(0, (0.5+u)*b, (0.5-v)*c, "Ga"),
26
+ Atom.new(0, (0.5-u)*b, (0.5+v)*c, "Ga")]
27
+ super(atoms, [v1, v2, v3])
28
+ end
29
+ end
30
+ end
31
+
@@ -17,16 +17,17 @@ module Aims
17
17
  # The relaxation constraints of this atom
18
18
  attr_accessor :constrain
19
19
  # Two atoms are equal if their coordinates are the same to this precision
20
- attr_accessor :precision
20
+ attr_accessor :precision # Seems like it should really be a class variable
21
21
 
22
22
  include Enumerable
23
23
 
24
24
  # Create an atom of the specified species at the given coordinates
25
- # * +x+ The x coordinate of the atom in angstrom
26
- # * +y+ The y coordinate of the atom in angstrom
27
- # * +z+ The z coordinate of the atom in angstrom
28
- # * +s+ The atomic species ex. "C", "Si", "S", etc. (can be nil)
29
- # * +c+ The relaxation constraints. valid values are TRUE, FALSE, ".true.", ".false.", "x", "y", "z" or %w(x y z)
25
+ # @param [Float] x The x coordinate of the atom in angstrom
26
+ # @param [Float] y The y coordinate of the atom in angstrom
27
+ # @param [Float] z The z coordinate of the atom in angstrom
28
+ # @param [String, nil] s The atomic species ex. "C", "Si", "S", etc. (can be nil)
29
+ # @param [Boolean, String, Array<String>] c The relaxation constraints. valid values are TRUE, FALSE, ".true.", ".false.", "x", "y", "z" or %w(x y z)
30
+ # @return [Atom] a new Atom
30
31
  def initialize(x=nil, y=nil, z=nil, s=nil, c=Array.new)
31
32
  self.x = x
32
33
  self.y = y
@@ -93,11 +94,19 @@ module Aims
93
94
  Math.sqrt((self.x - atom.x)**2 + (self.y - atom.y)**2 + (self.z - atom.z)**2)
94
95
  end
95
96
 
96
- # A deep copy of the atom
97
+ # A deep copy of the atom, but with a unique id
97
98
  def copy
98
99
  Atom.new(self.x, self.y, self.z, self.species, self.constrain)
99
100
  end
100
101
 
102
+ # An exact clone of the atom. Same ID and everything
103
+ def clone
104
+ a = Atom.new(self.x, self.y, self.z, self.species, self.constrain)
105
+ a.id = self.id
106
+ return a
107
+ end
108
+
109
+
101
110
  # Return a new atom with the same species and relaxation constraints
102
111
  # but with coordinates displaced by +x+, +y+, +z+
103
112
  def displace(x,y,z)
@@ -99,8 +99,8 @@ module Aims
99
99
  # Return the atoms in this unit cell. By default returns
100
100
  # only the visible atoms, but this method will return all of the atoms
101
101
  # if called with (visibleOnly = false)
102
- def atoms(visibleOnly = true)
103
- if visibleOnly and 0 < @clip_planes.size
102
+ def atoms(visibility = :visibleOnly)
103
+ if (visibility == :visibleOnly) and (0 < @clip_planes.size)
104
104
  @visibleAtoms
105
105
  else
106
106
  @atoms
@@ -237,7 +237,7 @@ module Aims
237
237
 
238
238
  # Recompute the atoms that are behind all the clip planes
239
239
  # Atoms that are in front of any clip-plane are considered invisible.
240
- def recache_visible_atoms
240
+ def recache_visible_atoms(makeBonds = false)
241
241
 
242
242
  plane_count = (@clip_planes ? @clip_planes.length : 0)
243
243
  return if plane_count == 0
@@ -255,7 +255,7 @@ module Aims
255
255
  @visibleAtoms << a if i == 0
256
256
  }
257
257
 
258
- make_bonds
258
+ make_bonds if makeBonds
259
259
  end
260
260
 
261
261
  # Rotate the geometry in 3 dimensions. The rotation is
@@ -312,6 +312,7 @@ module Aims
312
312
  atoms.size
313
313
  end
314
314
 
315
+
315
316
  # Return a two element array contaiing two artificial Aims::Atom objects whose coordinates
316
317
  # represent the lower-left and upper-right corners of the Geometry's bounding box.
317
318
  def bounding_box(visible_only = true)
@@ -377,7 +378,7 @@ module Aims
377
378
 
378
379
  # Return a new unit cell with all the atoms displaced by the amount x,y,z
379
380
  def displace(x,y,z)
380
- Geometry.new(atoms.collect{|a|
381
+ Geometry.new(atoms(:all).collect{|a|
381
382
  a.displace(x,y,z)
382
383
  }, self.lattice_vectors)
383
384
  #TODO copy miller indices
@@ -401,9 +402,9 @@ module Aims
401
402
  nz_sign = (0 < nz) ? 1 : -1
402
403
 
403
404
  new_atoms = []
404
- nx.abs.times do |i|
405
- ny.abs.times do |j|
406
- nz.abs.times do |k|
405
+ nx.to_i.abs.times do |i|
406
+ ny.to_i.abs.times do |j|
407
+ nz.to_i.abs.times do |k|
407
408
  new_atoms << self.displace(nx_sign*i*v1[0] + ny_sign*j*v2[0] + nz_sign*k*v3[0],
408
409
  nx_sign*i*v1[1] + ny_sign*j*v2[1] + nz_sign*k*v3[1],
409
410
  nx_sign*i*v1[2] + ny_sign*j*v2[2] + nz_sign*k*v3[2]).atoms
@@ -3,7 +3,17 @@ module Aims
3
3
 
4
4
  # Utility class for parsing an Aims geometry file
5
5
  # Example Usage:
6
- # uc = Aims::GeometryParser.parse("geometry.in")
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
7
17
  class GeometryParser
8
18
 
9
19
  # Parse a String representation of a geometry.in file
@@ -150,6 +150,7 @@ module Aims
150
150
  total += a[1][:cpu_time]
151
151
  }
152
152
  end
153
+
153
154
  end
154
155
 
155
156
  # A single self-consistency iteration
@@ -231,6 +232,7 @@ module Aims
231
232
  self.geometry_steps = Array.new
232
233
  self.geometry_converged = false
233
234
  self.timings = {}
235
+ self.computational_steps = Array.new
234
236
  end
235
237
 
236
238
  # Returns the best available value of the total energy
@@ -411,8 +413,8 @@ module Aims
411
413
 
412
414
  when /Begin self-consistency iteration/
413
415
  retval.geometry_step.sc_iterations << SCIteration.new
414
-
415
- when /End self-consistency iteration/, /End scf initialization - timings/
416
+
417
+ when /End self-consistency iteration/, /End scf initialization - timings/, /End scf reinitialization - timings/
416
418
  retval.sc_iteration.timings = OutputParser.parse_sc_timings(f)
417
419
 
418
420
  when /Change of charge density/
@@ -4,8 +4,11 @@ module Aims
4
4
  # of four points. The normals of the planes must all point outward. This is tested
5
5
  #
6
6
  class Volume
7
-
8
- include Vectorize
7
+
8
+ # Add Vectorize as class methods
9
+ class<<self
10
+ include Vectorize
11
+ end
9
12
 
10
13
  # Quick recursive method for calculating combinations
11
14
  def Volume.choose(list, num, head = [])
@@ -31,6 +34,8 @@ module Aims
31
34
  # Return an array of tuples that define the
32
35
  # vertices of intersection of these planes
33
36
  # Vertices are removed that lie in front of any plane
37
+ # @param [Array<Plane>] planes An array of Planes that define the boundaries of the volume
38
+ # @return [Array] An array of tuples that define the vertices of intersection of these planes
34
39
  def Volume.intersection_points(planes)
35
40
  combos = Volume.choose(planes, 3)
36
41
  points = []
@@ -46,43 +46,45 @@ module Aims
46
46
  end
47
47
 
48
48
  # Fill the given volume with atoms
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
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
86
88
 
87
89
  # Return a unit cell for a slab of 001
88
90
  # Specify the number of atomic monolayers,
@@ -107,7 +109,7 @@ module Aims
107
109
  if 0 < vacuum
108
110
  # Add vacuum
109
111
  monolayerSep = v3[2]/2
110
- zb.lattice_vectors[2] = Vector[0, 0, monolayers*monolayerSep.abs + vacuum.to_f]
112
+ zb.lattice_vectors[2] = Vector[0, 0, (monolayers-1)*monolayerSep.abs + vacuum.to_f]
111
113
  # Move everything into a nice tidy unit cell.
112
114
  zb = zb.correct
113
115
  end
@@ -192,7 +194,7 @@ module Aims
192
194
  zb = zb.repeat(1,1,monolayers+1)
193
195
 
194
196
  bilayerSep = v3[2]
195
- zb.lattice_vectors[2] = Vector[0, 0, monolayers*(bilayerSep.abs) + vacuum]
197
+ zb.lattice_vectors[2] = Vector[0, 0, (monolayers-1)*(bilayerSep.abs) + vacuum]
196
198
 
197
199
  # Strip off the top and bottom atom
198
200
  minZ = zb.atoms.min{|a,b| a.z <=> b.z}.z
@@ -287,10 +289,10 @@ module Aims
287
289
  zb = zb.repeat(1,1,monolayers)
288
290
 
289
291
 
292
+ monolayerSep = v3[2]
290
293
  if 0 < vacuum
291
294
  # Add vacuum
292
- monolayerSep = v3[2]
293
- zb.lattice_vectors[2] = Vector[0, 0, monolayers*monolayerSep.abs + vacuum.to_f]
295
+ zb.lattice_vectors[2] = Vector[0, 0, (monolayers-1)*monolayerSep.abs + vacuum.to_f]
294
296
  # Move everything into a nice tidy unit cell.
295
297
  zb = zb.correct
296
298
  end
@@ -34,6 +34,13 @@ describe ZincBlende do
34
34
  s.atoms.size.should eq(6)
35
35
  end
36
36
 
37
+ it "should have 20AA of vacuum" do
38
+ maxz = s.atoms.max{|a,b| a.z <=> b.z}.z
39
+ minz = s.atoms.min{|a,b| a.z <=> b.z}.z
40
+ z_vector = s.lattice_vectors[2][2]
41
+ (z_vector - (maxz - minz)).should eq (20)
42
+ end
43
+
37
44
  it "should have i constrained atoms" do
38
45
  s.atoms.find_all{|a| a.constrained?}.size.should eq(i)
39
46
  end
@@ -49,6 +56,13 @@ describe ZincBlende do
49
56
  # The 110 surface has 2 atoms per monolayer
50
57
  s.atoms.size.should eq(i*2)
51
58
  end
59
+
60
+ it "should have 20AA of vacuum" do
61
+ maxz = s.atoms.max{|a,b| a.z <=> b.z}.z
62
+ minz = s.atoms.min{|a,b| a.z <=> b.z}.z
63
+ z_vector = s.lattice_vectors[2][2]
64
+ (z_vector - (maxz - minz)).should eq (20)
65
+ end
52
66
  end
53
67
 
54
68
  5.times do |i|
@@ -59,5 +73,18 @@ describe ZincBlende do
59
73
  end
60
74
  end
61
75
 
76
+ context "111 Slab" do
77
+ s = zb.get_110_surface(5, 20)
78
+ it "should have 10 atoms" do
79
+ # The 110 surface has 2 atoms per monolayer
80
+ s.atoms.size.should eq(10)
81
+ end
82
+ it "should have 20AA of vacuum" do
83
+ maxz = s.atoms.max{|a,b| a.z <=> b.z}.z
84
+ minz = s.atoms.min{|a,b| a.z <=> b.z}.z
85
+ z_vector = s.lattice_vectors[2][2]
86
+ (z_vector - (maxz - minz)).should eq (20)
87
+ end
88
+ end
62
89
 
63
90
  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.0
4
+ version: 0.2.1
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-06-03 00:00:00.000000000Z
12
+ date: 2012-08-01 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &3812490 !ruby/object:Gem::Requirement
16
+ requirement: &3864410 !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: *3812490
24
+ version_requirements: *3864410
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
@@ -40,6 +40,7 @@ files:
40
40
  - lib/aims/geometry_parser.rb
41
41
  - lib/aims/output.rb
42
42
  - lib/aims/plane.rb
43
+ - lib/aims/Tetragonal.rb
43
44
  - lib/aims/vectorize.rb
44
45
  - lib/aims/volume.rb
45
46
  - lib/aims/wurtzite.rb
@@ -80,3 +81,4 @@ test_files:
80
81
  - spec/bond_spec.rb
81
82
  - spec/output_spec.rb
82
83
  - spec/zinc_blende_spec.rb
84
+ has_rdoc: