aims_project_windows 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
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