aims 0.2.0 → 0.2.1

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