aims_project_windows 0.3.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.
data/README ADDED
@@ -0,0 +1,5 @@
1
+
2
+ Required Gems:
3
+
4
+ ruby-opengl >= 0.60.1
5
+ wxruby
data/bin/AimsCalc ADDED
@@ -0,0 +1,367 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #
4
+ # AimsCalc [geometry] [control]
5
+ #
6
+ # Author: Joshua Shapiro, 2012
7
+ # email: joshua.shapiro@gmail.com
8
+ #
9
+ # Generate a set of FHI-AIMS calculations from control and geometry files.
10
+ # If the user provides filename on the command line the calculation is generated,
11
+ # otherwise, the user is prompted for filenames.
12
+ #
13
+
14
+ begin
15
+ require 'aims_project'
16
+ require 'highline'
17
+ rescue
18
+ require 'rubygems'
19
+ require 'aims_project'
20
+ end
21
+
22
+ def usage
23
+ STDERR.puts <<-END_USAGE
24
+ usage: AimsCalc command [args]
25
+ Valid commands are:
26
+ create - Create a new calculation
27
+ restart - Restart an aborted or cancelled calculation using most recent geometry
28
+ rerun - Rerun a calculation using the original geometry and control
29
+ rename - Rename a control or geometry file and all dependent calculations
30
+ invalidate - Invalidate a geometry or control file and dependent calculations
31
+ hold - Place a STAGED calculation into a HOLD status
32
+ release - Release a calculation from HOLD, placing it back in STAGED status
33
+ setvar - Set a calculation variable
34
+ help cmd - For help on a given command
35
+ END_USAGE
36
+ end
37
+
38
+ def help(cmd)
39
+ case cmd
40
+ when /create/
41
+ puts <<-HELP
42
+ usage: AimsCalc create [geometry] [control]
43
+ Create and stage a new calculation.
44
+ * geometry is the name of a geometry file
45
+ * control is the name of a control file
46
+
47
+ Without arguments, the user will be prompted to select geometry and control files.
48
+
49
+ HELP
50
+ when /restart/
51
+ puts <<-HELP
52
+ usage: AimsCalc restart [calculation]
53
+ Restart an aborted or cancelled calculation using most recent available geometry.
54
+ * The name of a calculation
55
+
56
+ Without arguments, the user will be prompted to select a calculation.
57
+
58
+ HELP
59
+ when /status/
60
+ puts <<-HELP
61
+ usage: AimsCalc status
62
+ Currently just dumps all the status files
63
+ HELP
64
+ when /rerun/
65
+ puts <<-HELP
66
+
67
+ usage: AimsCalc rerun [calculation]
68
+
69
+ Use this to rerun a calculation for whatever reason. This will
70
+ set the calculation status back to staged. run cap aims:enqueue to
71
+ actually rerun the calculation.
72
+ HELP
73
+ when /rename/
74
+ puts <<-HELP
75
+
76
+ usage: AimsCalc rename [control or geometry]
77
+
78
+ Renames a control or geometry file and all dependent calculations.
79
+ HELP
80
+ when /invalidate/
81
+ puts <<-HELP
82
+
83
+ usage: AimsCalc invalidate [geometry or control]
84
+
85
+ Invalidate a geometry or control file. This will mark the geometry
86
+ or control file as well as any dependent calculations as INVALID.
87
+ A warning will be issued if the user tries to use the INVALID input file.
88
+ HELP
89
+ when /hold/
90
+ puts <<-HELP
91
+
92
+ usage: AimsCalc hold calculation
93
+
94
+ Place a calculation that is currently STAGED into a HOLD status. This means it will
95
+ not be QUEUED for calculation. Use 'release' to re-STAGE the calculation.
96
+ HELP
97
+ when /release/
98
+ puts <<-HELP
99
+
100
+ usage: AimsCalc release calculation
101
+
102
+ Set the status for a calculation that is currently on HOLD status to STAGED.
103
+ This means it will be scheduled for execution the next time enqueue is run.
104
+ HELP
105
+
106
+ when /setvar/
107
+ puts <<-HELP
108
+
109
+ usage: AimsCalc setvar var1=value1 var2=value2 ...
110
+
111
+ Set a project variable. These variables are available for use in
112
+ geometry and control files using embedded ruby with the @var syntax.
113
+
114
+ ex.
115
+ AimsCalc setvar lattice_const=5.65
116
+
117
+ Then in a geometry file
118
+ atom 0 0 0 Ga
119
+ atom <%= [@gaas_lattice_const/4 @gaas_lattice_const/4 @gaas_lattice_const/4].join(" ") %> As
120
+
121
+ HELP
122
+
123
+ else
124
+ usage
125
+ end
126
+ end
127
+
128
+ # Get the project associated with the current directory
129
+ # returns nil if unable to find a project
130
+ def project
131
+ project_obj_files = Dir["*.yaml"]
132
+ unless project_obj_files.empty?
133
+ AimsProject::Project.load(project_obj_files.first)
134
+ else
135
+ raise AimsProject::AimsProjectException.new("Sorry, I can't tell what project this is. Please move to the project root directory.")
136
+ end
137
+ end
138
+
139
+ # Parse command line arguments of the form a=1 b=2 into a hash
140
+ # suitable for evaluating in the project binding
141
+ def parse_vars(args)
142
+ vars = {}
143
+
144
+ # Condition format of input user variables
145
+ args.each{|arg|
146
+ if arg =~ /(.*)=(.*)/
147
+ # Split key=value pairs
148
+ symbol = $1
149
+ value = $2
150
+ # Prefix all variables with an @
151
+ sym = if symbol.to_s =~ /^@.*/
152
+ symbol.to_sym
153
+ else
154
+ ("@" + symbol.to_s).to_sym
155
+ end
156
+
157
+ # Cast value to Float if applicable
158
+ val = if value =~ /^(\d+\.*\d*)$/
159
+ $1.to_f
160
+ elsif value =~ /"(.*)"/ or value =~ /'(.*)'/
161
+ $1
162
+ else
163
+ value
164
+ end
165
+
166
+ # Set the variable in the Vars hash
167
+ vars[sym] = val
168
+ end
169
+ }
170
+ vars
171
+ end
172
+
173
+ # Create a calculation from a geometry and control file.
174
+ # @param [String] geometry The name of a file that can be found in the geometry directory
175
+ # @param [String] control The name of a file that can be found in the control directory
176
+ # @param [Array<String>] args An array of string key-value pairs in the form of "key=value"
177
+ # These key-value pairs will be loaded as instance variables into the binding that
178
+ # is used to evaluate geometry and control.
179
+ def build_calculation(geometry, control, args)
180
+ begin
181
+ # a hash to store the user defined variables
182
+ vars = parse_vars(args)
183
+ # Load the project variables
184
+ p = project
185
+ calc = AimsProject::Calculation.create(p, geometry, control, vars)
186
+ puts "Created #{calc.calculation_directory}"
187
+ rescue
188
+ puts $!.message
189
+ puts $!.backtrace
190
+ end
191
+ end
192
+
193
+ # Generate a new calculation by calling Calculation::restart_relaxation
194
+ def restart_calculation(calculation)
195
+ calc = begin
196
+ AimsProject::Calculation.load(calculation)
197
+ rescue ObjectFileNotFoundException
198
+ calc_dir = File.join(AimsProject::CALCULATION_DIR, File.basename(calculation))
199
+ calc = AimsProject::Calculation.load(calc_dir)
200
+ end
201
+ newcalc = calc.restart_relaxation
202
+ puts "Created #{newcalc.name}"
203
+ end
204
+
205
+ # Print status information of each calculation
206
+ def calc_statuses
207
+ def date_str_fmt(dt)
208
+ case dt
209
+ when nil
210
+ "N/A"
211
+ when Date.today
212
+ "Today at " + dt.strftime("%H:%M")
213
+ when Date.today.prev_day
214
+ "Yesterday"
215
+ else
216
+ dt.strftime("%Y-%m-%d")
217
+ end
218
+ end
219
+ def duration_fmt(t)
220
+ if t < 2
221
+ "%0.2f hrs" % (t.to_f.abs*24.0)
222
+ else
223
+ "%i days ago" % t.round
224
+ end
225
+ end
226
+ def status_fmt(s)
227
+ color = case s
228
+ when AimsProject::RUNNING
229
+ :green
230
+ when AimsProject::COMPLETE
231
+ :yellow
232
+ when AimsProject::CANCELED
233
+ :red
234
+ else
235
+ nil
236
+ end
237
+ HighLine.color(s,color)
238
+ end
239
+ project_obj_files = Dir["*.yaml"]
240
+ project = AimsProject::Project.load(project_obj_files.first)
241
+ format = "%-40s\t%-30s\t%-15s\t%-15s\t%-15s\t%-15s"
242
+ puts format % ["GEOMETRY", "CONTROL", "STATUS", "CREATED_AT", "UPDATED_AT", "SINCE_UPDATE"]
243
+ project.calculations.sort{|a, b| a.updated_at <=> b.updated_at}.each{|c|
244
+ puts format % [c.geometry[0..40], c.control[0..30], status_fmt(c.status), date_str_fmt(c.created_at), date_str_fmt(c.updated_at), duration_fmt(DateTime.now - c.updated_at)]
245
+ }
246
+ end
247
+
248
+ # Place the specified calculations on HOLD status if they are staged.
249
+ def hold(calculation)
250
+ calc = get_calculation_from_string(calculation)
251
+ if calc.hold
252
+ puts "Calculation status set to #{calc.status}. Use AimsCalc release to revert to STAGED"
253
+ else
254
+ puts "Unable to set status of calculation to HOLD"
255
+ end
256
+ end
257
+
258
+ # Release a calculation from HOLD status
259
+ def release(calculation)
260
+ calc = get_calculation_from_string(calculation)
261
+ if calc.release
262
+ puts "Calculation status set to #{calc.status}."
263
+ else
264
+ puts "Unable to release calculation from HOLD"
265
+ end
266
+ end
267
+
268
+ # Set the calculation status back to staged
269
+ def rerun_calculation(calculation)
270
+ calc = begin
271
+ AimsProject::Calculation.load(calculation)
272
+ rescue ObjectFileNotFoundException
273
+ calc_dir = File.join(AimsProject::CALCULATION_DIR, File.basename(calculation))
274
+ calc = AimsProject::Calculation.load(calc_dir)
275
+ end
276
+ calc.status = AimsProject::STAGED
277
+ calc.save
278
+ puts "Calculation status set to STAGED. Run cap aims:enqueue to execute."
279
+ puts
280
+ end
281
+
282
+ def get_calculation_from_string(str)
283
+ calc = begin
284
+ AimsProject::Calculation.load(str)
285
+ rescue ObjectFileNotFoundException
286
+ calc_dir = File.join(AimsProject::CALCULATION_DIR, File.basename(str))
287
+ calc = AimsProject::Calculation.load(calc_dir)
288
+ end
289
+ calc
290
+ end
291
+
292
+ # Rename a geometry or control file and all dependent calculations
293
+ # @param file The name of the original file
294
+ # @param newname The new name for the file
295
+ def rename(file, newname)
296
+ raise "Sorry... 'AimsCalc rename' isn't implemented yet."
297
+ end
298
+
299
+ # Set project variables
300
+ def setvar(args)
301
+ vars = parse_vars(args)
302
+ p = project
303
+ vars.each{|sym, val|
304
+ p.instance_variable_set(sym, val)
305
+ puts "Setting #{sym} = #{val}"
306
+ }
307
+ p.save
308
+ end
309
+
310
+ # Invalidate each of the geometry or control inputs specified in arguments
311
+ def invalidate(args)
312
+ args.each {|arg|
313
+ files = Dir.glob(File.join(AimsProject::GEOMETRY_DIR, arg))
314
+ files += Dir.glob(File.join(AimsProject::CONTROL_DIR, arg))
315
+ files.each{|f|
316
+ # Write a note in file header
317
+ puts "I would invalidate #{f} here if I was implemented..."
318
+ # Find all the dependent calculations
319
+
320
+ # and set their status to invalid
321
+
322
+ }
323
+ }
324
+ end
325
+
326
+ # Run the desired command
327
+ begin
328
+ args = ARGV
329
+ cmd = args.shift
330
+ case cmd
331
+ when /create/
332
+ build_calculation(args[0], args[1], args[2..-1])
333
+ when /restart/
334
+ restart_calculation(args[0])
335
+ when /status/
336
+ calc_statuses
337
+ when /rerun/
338
+ rerun_calculation(args[0])
339
+ when /invalidate/
340
+ invalidate(args)
341
+ when /rename/
342
+ rename(args[0], args[1])
343
+ when /hold/
344
+ hold(args)
345
+ when /release/
346
+ release(args)
347
+ when /setvar/
348
+ setvar(args)
349
+ when /help/
350
+ help(args[0])
351
+ else
352
+ usage
353
+ end
354
+ rescue AimsProject::AimsProjectException => ex
355
+ STDERR.puts ex.message
356
+ rescue => error
357
+ STDERR.puts
358
+ STDERR.puts "Sorry, something went wrong. Please send the following information to joshua.shapiro@gmail.com"
359
+ STDERR.puts
360
+ STDERR.puts "FILE: #{__FILE__}"
361
+ STDERR.puts "CMD: #{cmd}"
362
+ STDERR.puts "ARGS: #{args.join(" ")}"
363
+ STDERR.puts "ERROR: " + error.message
364
+ STDERR.print "\t" + error.backtrace.slice(0..5).join("\n\t")
365
+ STDERR.puts
366
+ STDERR.puts
367
+ end
data/bin/AimsProject ADDED
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env ruby
2
+ require 'aims_project'
3
+ require 'fileutils'
4
+ require 'highline'
5
+
6
+ # Initialize an AimsProject
7
+ # Create a directory named by the project
8
+ # and generate the AimsProjectInfo.yaml file
9
+
10
+ ui = HighLine.new
11
+ skeleton_dir = File.join(Dir.home, ".aims_project")
12
+
13
+ unless File.exists?(skeleton_dir)
14
+ ui.say <<-EOF
15
+
16
+ It looks like this is the first time you are running AimsProject.
17
+
18
+ I can create the directory $HOME/.aims_project which will be the
19
+ template for all of your future projects. Feel free to customize the
20
+ files in this directory to suit your needs. In particular, you will
21
+ want to customize 'Capfile' and 'aims.sh'. And you may want to add
22
+ variables that should be available to any project in 'project_variables.rb'
23
+
24
+ EOF
25
+
26
+ # Copy the skeleton directory tasks into config
27
+ script_dir = File.join(File.dirname(File.expand_path(__FILE__)), '..', 'skeleton')
28
+
29
+ if ui.agree("Can I create #{Dir.home}/.aims_project?")
30
+ # Create the skeleton directory in $HOME/.aims_project
31
+ Dir.mkdir skeleton_dir
32
+ FileUtils.cp_r(File.join(script_dir, '.'), skeleton_dir)
33
+ else
34
+ ui.say("Ok, maybe next time.")
35
+ skeleton_dir = script_dir
36
+ end
37
+ end
38
+
39
+ # Set the project name and direcory
40
+ projectName = ARGV[0]
41
+ unless projectName
42
+ projectName = ui.ask("Please specify the name of the project: ", String) {|q| q.whitespace = :remove}.to_s
43
+ end
44
+
45
+ projectDir = projectName
46
+
47
+ if project = AimsProject::Project.create(projectName)
48
+
49
+ ui.say "Creating #{projectDir}..."
50
+
51
+ # save the project into a directory named after the project
52
+ project.save(projectDir)
53
+
54
+ # Copy the skeleton directory tasks into config
55
+ FileUtils.cp_r(File.join(skeleton_dir, '.'), projectDir)
56
+
57
+
58
+ # Generate the default Capfile
59
+ capfile = ""
60
+ File.open(File.join(projectDir, "Capfile"), 'r') do |capfile_template|
61
+ capfile_template.each_line do |line|
62
+ line.sub!(/__PROJECT_DIR__/, projectDir)
63
+ line.sub!(/__PROJECT_NAME__/, projectName)
64
+ capfile << line
65
+ end
66
+ end
67
+
68
+ File.open(File.join(projectDir, "Capfile"), 'w') do |f|
69
+ f.puts capfile
70
+ end
71
+
72
+ STDOUT.puts <<-EOL
73
+
74
+ Done creating the aims project #{projectName}. Here are the steps to get started.
75
+ 1) Customize the variables in #{File.join(projectDir, "Capfile")}
76
+ 2) Add geometry files to the directory #{File.join(projectDir, AimsProject::GEOMETRY_DIR)}
77
+ 3) Add control files to the directory #{File.join(projectDir, AimsProject::CONTROL_DIR)}
78
+ 4) Generate a calculation with the command:
79
+ AimsCalc create [geometry] [control]
80
+ 5) Execute the calculations with the command:
81
+ cap aims:enqueue
82
+
83
+ EOL
84
+
85
+ else
86
+ STDERR.puts "Error creating project."
87
+ STDERR.puts $!.message
88
+ end
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+
5
+ require "wx"
6
+ require "erb"
7
+ require "gl"
8
+ require "glu"
9
+
10
+ require 'aims'
11
+ require 'aims_project'
12
+ require 'aims_project/material.rb'
13
+ require 'aims_project/atom.rb'
14
+ require 'aims_project/inspector.rb'
15
+ require 'aims_project/crystal_viewer.rb'
16
+ require 'aims_project/geometry_editor.rb'
17
+ require 'aims_project/geometry_console.rb'
18
+ require 'aims_project/project_tree.rb'
19
+ require 'aims_project/calculation_tree.rb'
20
+ require 'aims_project/app_controller.rb'
21
+ require 'aims_project/geometry_window.rb'
22
+ require 'aims_project/calculation_window.rb'
23
+ require 'aims_project/thread_callback_event.rb'
24
+ require 'aims_project/crystal_viewer_options.rb'
25
+
26
+ controller = AimsProject::AppController.new
27
+
28
+ unless __FILE__.nil?
29
+ cwd = File.expand_path(".")
30
+ controller.working_dir = cwd
31
+ end
32
+
33
+
34
+ # project_obj_files = Dir["*.yaml"]
35
+ # controller.project = AimsProject::Project.load(project_obj_files.first) unless project_obj_files.empty?
36
+ AimsProject::ThreadCallbackEvent.set_event_type(Wx::Event.new_event_type)
37
+ Wx::EvtHandler.register_class(AimsProject::ThreadCallbackEvent, AimsProject::ThreadCallbackEvent.event_type, "evt_thread_callback", 0)
38
+
39
+ controller.main_loop
@@ -0,0 +1,42 @@
1
+
2
+ module AimsProject
3
+ class AimsProjectException < StandardError
4
+ end
5
+
6
+ class InvalidFilenameException < AimsProjectException
7
+ def initialize(filename)
8
+ if filename.nil?
9
+ super "No filename specified"
10
+ else
11
+ super "The filename #{filename} is invalid."
12
+ end
13
+ end
14
+ end
15
+
16
+ class ObjectFileNotFoundException < AimsProjectException
17
+ def initialize(filename)
18
+ super "The serialized yaml file was not found: #{filename}"
19
+ end
20
+ end
21
+
22
+ class CorruptObjectFileException < AimsProjectException
23
+ def initialize(filename)
24
+ super "The serialized yaml file is corrupt: #{filename}"
25
+ end
26
+ end
27
+
28
+ class GeometryValidationException < AimsProjectException
29
+ attr_reader :violations
30
+ def initialize(violations)
31
+ @violations = violations
32
+ super "The Geometry failed validation."
33
+ end
34
+ end
35
+
36
+ class GeometryEvaluationException < AimsProjectException
37
+ def initialize
38
+ super "Error evaluating geometry"
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,52 @@
1
+ module AimsProject
2
+
3
+ # A class that encapsulates the Aims::Geometry and other
4
+ # state information important for AimsProject
5
+ class AimsProjectGeometry
6
+
7
+ # Boolean flag indicating whether the atoms should be displaced to all lie
8
+ # within the unit cell
9
+ attr_accessor :correct_geometry
10
+
11
+ # The filename defining this geometry
12
+ attr_reader :filename
13
+
14
+ def initialize(file)
15
+ @filename = file
16
+ @geometry_original = Aims::GeometryParser.parse(@filename)
17
+ end
18
+
19
+ def geometry
20
+ if self.correct_geometry
21
+ geometry_corrected
22
+ else
23
+ geometry_original
24
+ end
25
+ end
26
+
27
+ def geometry_corrected
28
+ if @geometry_corrected.nil?
29
+ @geometry_corrected = @geometry_original.correct
30
+ end
31
+ @geometry_corrected
32
+ end
33
+
34
+ def geometry_original
35
+ @geometry_original
36
+ end
37
+
38
+ def to_s
39
+ @filename
40
+ end
41
+
42
+
43
+ def save
44
+ unless @filename
45
+ raise InvalidFilenameException
46
+ end
47
+ raise "AimsProjectGeometry.save is not yet implemented"
48
+ end
49
+
50
+ end
51
+
52
+ end