Class: CodeRunner::Run::FortranNamelist

Inherits:
CodeRunner::Run show all
Defined in:
lib/coderunner/fortran_namelist.rb

Overview

This is a class which is has several methods to facilitate the generation of input files for simulation codes which use a Fortran namelist style input file.

Those developing a code module to deal with such a simulation code can make their custom run class a subclass of this class, and take advantage of all its functionality.

There is a convention introduced by this class:

* a "code_variable" is a variable name as it appears in the simulation code
* a "variable" is a variable name as it appears in and is referred to by CodeRunner

Why is this necessary? Every variable in CodeRunner has to have a unique,lowercase name. In contrast, in the simulation code, variables in different namelists can have the same name, and this name may contain uppercase letters. To get around this problem, when it occurs, a new CodeRunner name is defined and the name as it appears in the simulation code (which is referred to as the code_variable), is stored in the database as :code_name.

Constant Summary collapse

FORTRAN_SINGLE_LINE =

FORTRAN_SINGLE_LINE = /(?:(?:&s*)|(?:[ t]*!.*)|[^!nr])*/ FORTRAN_SINGLE_LINE = /(?:(?:&s*)|(?:&[ t]*!.*)|[^!nr])*/

/(?:
(?:&[ \t]*\r?\n? #continuing line with 
 	(?:[ \t]*!.*\r?\n?)+) # multiple comments 
|
  (?:&\s*[\n\r]+) # continuing line
|
	[^!\n\r])*   # non continuing line
/x

Instance Attribute Summary

Attributes inherited from CodeRunner::Run

#code, #code_runner_version, #executable_name, #max_complete, #maxes, #naming_pars, #nprocs, #real_id, #run_test_flags, #runner, #sys, #version

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from CodeRunner::Run

#analyse_input_file_text, #cache, check_and_update, #code_run_environment, #comment_line, #create_phantom, #data_string, #defaults_file_name, #defaults_location, #dup, #evaluate_defaults_file, #executable_location, #execute_submission, finish_setting_up_class, #generate_combined_ids, #generate_phantom_runs, #generate_run_name, #gets, gets, #hard_cache, #info_file, #initialize, #inspect, #is_complete, #job_identifier, #learn_from, load, #logiv, #max, #min, modify_job_script, #p, #prepare_submission, #pretty_print, #print, #process_directory, #puts, #rcp, rcp, #read_info, #read_results, #recheck, #results_file, #run_heuristic_analysis, #save, set_modlet, #smax, #smin, #try_by_system, #try_to_find_job_output_ends, #try_to_get_error_file, #try_to_get_job_number, #try_to_get_output_file, #update_in_queue, update_status, #update_submission_parameters, #write_info, #write_results

Constructor Details

This class inherits a constructor from CodeRunner::Run

Class Method Details

.add_code_variable_to_namelist(namelist, var, value) ⇒ Object

Add variable var, with a sample value, to namelist in the database of namelists. The parameter var should be the name of the variable as it appears in the simulation code.



288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'lib/coderunner/fortran_namelist.rb', line 288

def self.add_code_variable_to_namelist(namelist, var, value)
	code_name = var
	var = var.to_s.downcase.to_sym
	namelist = namelist.to_s.sub(/_(?<num>\d+)$/, '').to_sym
	enum = $~ ? $~[:num] : nil
	return if rcp.namelists[namelist] and rcp.namelists[namelist][:variables].map{|v, h| (h[:code_name] or v).to_s.downcase.to_sym}.include? var
	namelists = rcp.namelists
	namelist_file = 'namelists.rb'
# 	end
	raise "This namelist: #{namelist} should have an enumerator and does not have one" if enum and not @namelists[namelist][:enumerator]
	return unless Feedback.get_boolean("An unknown variable has been found in this input file: \n\n\t Namelist: #{namelist}, Name: #{code_name}, Sample Value: #{value.inspect}.\n\nDo you wish to add it to the CodeRunner module? (Recommended: answer yes as long as the variable is not a typo)")

	while nms = variable_exists?(namelist, var)
		puts "This variable: #{var} already exists in these namelists: #{nms}. Please give an alternative name for CodeRunner (this will not affect the name that appears in the input file). If you know that the variable has the same meaning in these other namelists, or if you know that none of these namelists will appear at the same time, enter '0' to leave it unchanged."
		ans = STDIN.gets.chomp
		break if ans == "0"
		var = ans.to_sym
	end
		
	namelists[namelist] ||= {}
	namelists[namelist][:description] ||= ""
	namelists[namelist][:should_include] ||= "true"
	namelists[namelist][:variables] ||= {}
	raise "Shouldn't have got here" if namelists[namelist][:variables][var]
	tst = nil

	case value
	when Float
		#tst = "Tst::FLOAT"
		newtst = "kind_of? Numeric"
		explanation = "This variable must be a floating point number (an integer is also acceptable: it will be converted into a floating point number)."
		type = :Float
	when Integer
		#tst = "Tst::INT"
		newtst = "kind_of? Integer"
		explanation = "This variable must be an integer."
		type = :Integer
	when *String::FORTRAN_BOOLS
		#tst = "Tst::FORTRAN_BOOL"
		newtst = "kind_of? String and FORTRAN_BOOLS.include? self"
		explanation = "This variable must be a fortran boolean. (In Ruby this is represented as a string: e.g. '.true.')" 
		type = :Fortran_Bool
	when String
		#tst = "Tst::STRING"
		newtst = "kind_of? String"
		explanation = "This variable must be a string."
		type = :String
	when Complex
		#tst = "true"
		newtst = "kind_of? Complex"
		explanation = "This variable must be a complex number."
		type = :Complex
	end
	namelists[namelist][:variables][var] = {
		should_include: "true", 
		description: nil, 
		help: nil, 
		code_name: code_name, 
		must_pass: [{
			test: newtst, 
			explanation: explanation
		}], 
		type: type
	}
	if enum
		attr_accessor (var + "_#{enum}").to_sym
	else
		attr_accessor var
	end
  save_namelists
	edit_variable_help(namelist, var)
# 	folder = File.dirname(__FILE__)
# 	File.open(folder + '/' + namelist_file, 'w'){|f| f.puts namelists.pretty_inspect}
end

.add_help_to_variable(namelist = , var = , help = ) ⇒ Object

Add help to the variable in the given namelist



276
277
278
279
280
281
# File 'lib/coderunner/fortran_namelist.rb', line 276

def self.add_help_to_variable(namelist=ARGV[-3], var=ARGV[-2], help=ARGV[-1])
#   p rcp.namelists[namelist.to_sym]
  rcp.namelists[namelist.to_sym][:variables][var.to_sym][:help] = help
  rcp.namelists[namelist.to_sym][:variables][var.to_sym][:description] ||= help
  save_namelists
end

.add_namelist_must_pass(namelist, tst) ⇒ Object

Add a test which the namelist must pass before being included in the input file. The parameter tst must be of the form: { test: test_string explanation: explanation_string } where test_string is a string such that run.instance_eval(test_string) should be true when the run to be submitted passes the test. The explanation should be a string which explains what the test does. If the run to be submitted fails the test, an error is raised.



438
439
440
441
442
443
# File 'lib/coderunner/fortran_namelist.rb', line 438

def self.add_namelist_must_pass(namelist, tst)
	rcp.namelists[namelist][:must_pass] ||= []
	rcp.namelists[namelist][:must_pass].push tst
	rcp.namelists[namelist][:must_pass].uniq!
	save_namelists
end

.add_namelist_should_pass(namelist, tst) ⇒ Object

Add a test which the namelist should pass before being included in the input file. The parameter tst must be of the form: { test: test_string explanation: explanation_string } where test_string is a string such that run.instance_eval(test_string) should be true when the run to be submitted passes the test. The explanation should be a string which explains what the test does. If the run to be submitted fails the test, a warning is given.



482
483
484
485
486
487
# File 'lib/coderunner/fortran_namelist.rb', line 482

def self.add_namelist_should_pass(namelist, tst)
	rcp.namelists[namelist][:should_pass] ||= []
	rcp.namelists[namelist][:should_pass].push tst
	rcp.namelists[namelist][:should_pass].uniq!
	save_namelists
end

.add_variable_must_pass(namelist = nil, var, tst) ⇒ Object

Add a test which the variable must pass before being included in the input file. The parameter tst must be of the form: { test: test_string explanation: explanation_string } where test_string is a string such that variable_value.instance_eval(test_string) should be true when the variable_value passes the test. The explanation should be a string which explains what the test does. If variable_value fails the test, an error is raised.



414
415
416
417
418
419
420
421
422
423
# File 'lib/coderunner/fortran_namelist.rb', line 414

def self.add_variable_must_pass(namelist=nil, var, tst)
	unless namelist
		namelist = rcp.namelists.find{|n, nh| nh[:variables].keys.include? var}[0]
		eputs "Editing namelist #{namelist}"; STDIN.gets
	end
	rcp.namelists[namelist][:variables][var][:must_pass] ||= []
	rcp.namelists[namelist][:variables][var][:must_pass].push tst
	rcp.namelists[namelist][:variables][var][:must_pass].uniq!
	save_namelists
end

.add_variable_should_pass(namelist = nil, var, tst) ⇒ Object

Add a test which the variable should pass before being included in the input file. The parameter tst must be of the form: { test: test_string explanation: explanation_string } where test_string is a string such that variable_value.instance_eval(test_string) should be true when the variable_value passes the test. The explanation should be a string which explains what the test does. If variable_value fails the test, a warning is given.



458
459
460
461
462
463
464
465
466
467
# File 'lib/coderunner/fortran_namelist.rb', line 458

def self.add_variable_should_pass(namelist=nil, var, tst)
	unless namelist
		namelist = rcp.namelists.find{|n, nh| nh[:variables].keys.include? var}[0]
		eputs "Editing namelist #{namelist}"; STDIN.gets
	end
	rcp.namelists[namelist][:variables][var][:should_pass] ||= []
	rcp.namelists[namelist][:variables][var][:should_pass].push tst
	rcp.namelists[namelist][:variables][var][:should_pass].uniq!
	save_namelists
end

.correct_namelist_casesObject

For backward compatibility: ensures that all variables (NB variables, not code_variables) are lower case in the namelist database



166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/coderunner/fortran_namelist.rb', line 166

def self.correct_namelist_cases
	rcp.namelists.each do |namelist, namelist_hash|
		namelist_hash[:variables].each do |var, varhash|
			#p var
			if var.to_s =~ /[A-Z]/ or var.kind_of? String
				p var
				namelist_hash[:variables].delete(var)
				namelist_hash[:variables][var.to_s.downcase.to_sym] = varhash
			end
		end
	end
	save_namelists
end

.correct_type_locationObject

A one off function designed to correct an old error in the namelists



365
366
367
368
369
370
371
372
373
374
375
376
# File 'lib/coderunner/fortran_namelist.rb', line 365

def self.correct_type_location
	rcp.namelists.values.each do |namelist_hash|
		namelist_hash[:variables].each do |var, var_hash|
			if var_hash[:must_pass][0] and  var_hash[:must_pass][0][:type]
			 var_hash[:type] = 	 var_hash[:must_pass][0][:type]
			 var_hash[:must_pass][0].delete(:type)
			 #pp var_hash
			end
		end
	end
	save_namelists
end

.defaults_file_text_from_input_file(input_file) ⇒ Object



760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
# File 'lib/coderunner/fortran_namelist.rb', line 760

def self.defaults_file_text_from_input_file(input_file)
	string = defaults_file_header

	hash = parse_input_file(input_file)
	#pp hash; exit
	#ep ['class', self.to_s, 'namelists', rcp.namelists.keys, 'code_long', rcp.code_long, 'namelist_hashes', rcp.namelists.values.map{|v| v.class}]
	rcp.namelists.each do |namelist, namelist_hash|
 		#ep namelist
		if namelist_hash[:enumerator]  # ie. This is an indexed namelist
      #p namelist_hash[:enumerator]
			enumerator = namelist_hash[:enumerator][:name]
			enum_hash = hash.find{|nml, nmlh| nmlh[enumerator]}
			next unless enum_hash
			#pp enum_hash
			enum = enum_hash[1][enumerator]
			enum.times{|i| string << namelist_defaults_text(hash, namelist, namelist_hash, i+1)}
		else
			string << namelist_defaults_text(hash, namelist, namelist_hash)
		end
	end
	string
end

.delete_variable(namelist, var) ⇒ Object

Deletes the given variable from the namelists and saves the namelists



119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/coderunner/fortran_namelist.rb', line 119

def self.delete_variable(namelist, var)
	#variables_hash = rcp.namelists[namelist][:variables]
	#var_name = (variables_hash.find do |var_n, var_hash|
		#var_hash[:code_name] == var or var_n == var
	#end)[0]
	rcp.deleted_variables ||= {}
	rcp.deleted_variables[var] = rcp.namelists[namelist][:variables][var]
	rcp.namelists[namelist][:variables].delete(var)

	save_deleted_variables
	save_namelists
end

.diff_input_files(file1 = , file2 = ) ⇒ Object

This method compares two different input files and prints out a hash summarising the differences between them.



670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
# File 'lib/coderunner/fortran_namelist.rb', line 670

def self.diff_input_files(file1 = ARGV[2], file2 = ARGV[3])

  rcp.runner.update if [file1, file1].find{|file| file =~ /^\d+$/}
	file1, file2 = [file1, file2].map{|file| (run = rcp.runner.run_list[file.to_i]; file = "#{run.directory}/#{run.run_name}.in") if file.to_s =~ /^\d+$/; file}
	hash1 = generate_simple_namelist_hash(file1)
	hash2 = generate_simple_namelist_hash(file2)
	new_hash = {}
	(hash1.keys + hash2.keys).uniq.each do |key|
		unless hash1[key] and hash2[key]
			new_hash[key] = hash1[key] ? "Missing in #{File.basename(file2)} (Right)" : "Missing in #{File.basename(file1)} (Left)"
		else
			new_hash[key] = {}
			(hash1[key].keys + hash2[key].keys).uniq.each do |vkey|
# 				p vkey
				unless hash1[key][vkey].hash == hash2[key][vkey].hash
					new_hash[key][vkey] = [hash1[key][vkey], hash2[key][vkey]]
				end
			end
		end
	end
	eputs new_hash.pretty_inspect
end

.edit_namelist_help(namelist, message = "") ⇒ Object

Edit the help for the namelist. Requires the environment variable EDITOR to be set.

Raises:

  • (ArgumentError)


183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/coderunner/fortran_namelist.rb', line 183

def self.edit_namelist_help(namelist, message = "")
	raise ArgumentError.new("Unknown namelist #{namelist}") unless namelist_hash = rcp.namelists[namelist]
	raise "Please set the environment variable EDITOR" unless ENV['EDITOR']
	File.open('/tmp/.tmp_namelist_help.txt', 'w') do |file|
		file.puts <<EOF

------------------------------------------------------------------
Editing help and description for namelist #{namelist}:
-----------------------------------------------------------------

Edit the help and description, then save and quit the editor. Help can be long and detailed, and can include MediaWiki markup. Description should be short and in plain text.

#{message}

-------------------------------------begin help text


#{namelist_hash[:help]}


------------------------------------begin description

#{namelist_hash[:description]}
EOF
	end
	system "#{ENV['EDITOR']} /tmp/.tmp_namelist_help.txt"
	namelist_hash[:help], namelist_hash[:description] = File.read('/tmp/.tmp_namelist_help.txt').split(/^\-+begin help text/)[1].split(/^\-+begin description/, -1).map{|s| s.sub(/\A\s+/, '').sub(/\s+\Z/, '')}
	save_namelists
end

.edit_variable_help(namelist, var, message = "") ⇒ Object

Edit the help for the variable in var in the given namelist. Requires the environment variable EDITOR to be set.

Raises:

  • (ArgumentError)


216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/coderunner/fortran_namelist.rb', line 216

def self.edit_variable_help(namelist, var, message = "")
	raise ArgumentError.new("Unknown namelist,variable #{namelist},#{var}") unless namelist_hash = rcp.namelists[namelist] and var_hash = namelist_hash[:variables][var]
	raise "Please set the environment variable EDITOR" unless ENV['EDITOR']
	File.open('/tmp/.tmp_variable_help.txt', 'w') do |file|
		file.puts <<EOF

------------------------------------------------------------------
Editing help and description for #{var} in namelist #{namelist}:
-----------------------------------------------------------------

Edit the help and description, then save and quit the editor. Help can be long and detailed, and can include MediaWiki markup. Description should be short and in plain text.

#{message}

-------------------------------------begin help text


#{var_hash[:help]}


------------------------------------begin description

#{var_hash[:description]}
EOF
	end
	system "#{ENV['EDITOR']} /tmp/.tmp_variable_help.txt"
	var_hash[:help], var_hash[:description] = File.read('/tmp/.tmp_variable_help.txt').split(/^\-+begin help text/)[1].split(/^\-+begin description/, -1).map{|s| s.sub(/\A\s+/, '').sub(/\s+\Z/, '')}
	save_namelists
end

.find_variable_hash(var) ⇒ Object

Return the hash of variable properties if it exists. Else return nil



631
632
633
634
635
636
637
638
# File 'lib/coderunner/fortran_namelist.rb', line 631

def self.find_variable_hash(var)
	varhash = nil
	rcp.namelists.each do |namelist, hash|
		varhash  = hash[:variables][var]
		return varhash if varhash 
	end
	return nil
end

.fortran_type(varhash) ⇒ Object



1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
# File 'lib/coderunner/fortran_namelist.rb', line 1274

def fortran_type(varhash)
	case varhash[:type]
	when :Float
		'real'
	when :Fortran_Bool
		'logical'
	when :String
		'character'
	when :Integer
		'integer'
	else 
		raise 'unknown type'
	end
end

.get_aggregated_source_code_text(source_code_folder) ⇒ Object

Given the folder where the source code resides, return a single string containing all the code



1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
# File 'lib/coderunner/fortran_namelist.rb', line 1018

def self.get_aggregated_source_code_text(source_code_folder)
	#p 'source_code_folder', source_code_folder
	string = ""
	(rcp.source_code_subfolders.map{|f| '/' + f} + [""]).map{|f| source_code_folder + f}.each do |folder|
		Dir.chdir(folder) do 
			Dir.entries.each do |file|
				next unless file =~ /((\.f9[05])|(\.fpp))$/
				next if file =~ /ingen/
				ep file
				text = File.read(file) + "\n"
				text =~ /a/
				string += text
			end
		end
	end
	string
end

.get_variable_modules(folder = ) ⇒ Object Also known as: gvm

Work out which module a variable is found in



1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
# File 'lib/coderunner/fortran_namelist.rb', line 1223

def get_variable_modules(folder=ARGV[2])
	text = get_aggregated_source_code_text(folder)
	#puts text
	modules = {}
	regex = /^\s*module\s+(\w+)((?:.|\n)*?)^\s*end\s+module\s+\g<1>/i
	#regex = /^\s*module\s+(\w+\b)/i
		p regex
	text.scan(regex) do 
		p $~[1]
		modules[$~[1].to_sym] = $~[2]
	end
	#pp modules


	rcp.namelists.each do |nmlist, hash|
		hash[:variables].each do |var, varhash|
			#regex = Regexp.new("module\\s+(\\w+)(?:.|\\n)*?public.*?(#{var})(?:.|\\n)*?namelist(#{FORTRAN_SINGLE_LINE})(?:.|\\n)*?end\\s+module\\s+\\1")
			#regex = Regexp.new("module\\s+(\\w+)(?:.|\\n)*?public.*?(#{var})(?:.|\\n)*?namelist(#{FORTRAN_SINGLE_LINE})")
			#regex = Regexp.new("public.*?(#{var})(?:.|\\n)*?namelist#{FORTRAN_SINGLE_LINE}#{var}")
			regex = Regexp.new("namelist#{FORTRAN_SINGLE_LINE}#{var}")
			#p regex
		 modules.each  do |m, mod|
			 mod.scan(regex) do
			  varhash[:module] = m.to_sym		
			 end
		 end
		end
	end
save_namelists
end

.help_input(var = ARGV[2].to_sym) ⇒ Object

Print help for the given variable to STDOUT.



642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
# File 'lib/coderunner/fortran_namelist.rb', line 642

def self.help_input(var=ARGV[2].to_sym)
	eputs "\n------------ Help for '#{var}' -----------------"
	eputs "\n#{(rcp.variables_with_help[var] or "No help currently available")}\n"
	varhash = find_variable_hash(var)
  namelists = rcp.namelists.find_all{|namelist, hash| hash[:variables].keys.include? var.to_sym}.map{|n,h| n}
  eputs "\nFound in namelists: #{namelists.inspect}"
	return unless varhash
	eputs "This variable must take one of the following values: \n\t#{(varhash[:allowed_values] or varhash[:text_options])}" if (varhash[:allowed_values] or varhash[:text_options])
	eputs "\n-------- Autoscanned Defaults for '#{var}' --------------\n\nIf this variable is not specified it may be given one of these default values:\n\t#{rcp.variables_with_autoscanned_defaults[var].inspect.sub(/^\[/, '').sub(/\]$/, '')}\n in the code. These values have been automatically scanned from the source code and do not constitute a recommendation; they may raise an error."
	eputs "\n-------- Must Pass Tests for '#{var}' --------------\n\nThe variable must pass the following tests:\n\n"
	varhash[:must_pass].each do |hash|
		eputs "\tTest: #{hash[:test]}" 
		eputs "\tExplanation: #{hash[:explanation]}"
	end
	eputs
end

.help_variablesObject

Print out a list of every variable with help attached.



662
663
664
665
666
# File 'lib/coderunner/fortran_namelist.rb', line 662

def self.help_variables
	max_length = rcp.variables.map{|var| var.to_s.length}.inject{|old, new| [old,new].max}
	# + "-" * ([max_length - var.length - 8, 0].max)
	eputs rcp.variables_with_help.map{|var, comment| "#{var.to_s.rjust(max_length)}---> #{comment}"}.find_all{|string| not string =~ /^\s*\w+_[ie]/}
end

.known_code_variable?(namelist, var) ⇒ Boolean

Returns true if the code variable (which may correspond to the code name) is present in namelist

Returns:

  • (Boolean)


111
112
113
114
115
# File 'lib/coderunner/fortran_namelist.rb', line 111

def self.known_code_variable?(namelist, var)
	return true if rcp.namelists[namelist] and rcp.namelists[namelist][:variables].map{|(v,h)| (h[:code_name] or v).to_s.downcase.to_sym}.include? var.to_s.downcase.to_sym
# 	end
	return false
end

.make_new_defaults_file(name = , input_file = ) ⇒ Object

The name is self-explanatory: this method takes an input file and generates a CodeRunner defaults file. The first argument is the name of the new defaults file.



733
734
735
736
737
738
# File 'lib/coderunner/fortran_namelist.rb', line 733

def self.make_new_defaults_file(name=ARGV[-2], input_file=ARGV[-1])
	string = defaults_file_text_from_input_file(input_file)
	defaults_filename = "#{name}_defaults.rb"
	raise "This defaults name already exists" if FileTest.exist? defaults_filename
	File.open(defaults_filename, 'w'){|file| file.puts(string)}
end

.namelist_defaults_text(hash, namelist, namelist_hash, enum = nil) ⇒ Object

Called by defaults_file_text_from_input_file.



742
743
744
745
746
747
748
749
750
751
752
753
754
# File 'lib/coderunner/fortran_namelist.rb', line 742

def self.namelist_defaults_text(hash, namelist, namelist_hash, enum = nil)
	ext = enum ? "_#{enum}" : ""
	namelist = namelist + ext.to_sym
	return "" unless hash[namelist]
	text = "\n\n######################################\n# Defaults for namelist #{namelist}\n#######################################\n\n"
# 	pp hash[namelist]
	namelist_hash[:variables].each do |var, varhash|
		code_var = (varhash[:code_name] or var)
		cr_var = var + ext.to_sym
		text << "@#{cr_var} = #{hash[namelist][code_var].inspect}    # #{varhash[:description]}\n" if hash[namelist][code_var]
	end
	return text
end

.parse_input_file(input_file, strict = true) ⇒ Object Also known as: generate_simple_namelist_hash

Parses a Fortran namelist input file into a hash of { :namelist => { :variable => value } }



535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
# File 'lib/coderunner/fortran_namelist.rb', line 535

def self.parse_input_file(input_file, strict=true)
	if FileTest.file? input_file
		text = File.read(input_file)
	else
		text = input_file
	end
	namelist_hash = {}
	regex = Regexp.new("#{rcp.matching_regex.to_s}\\s*(?:\\!(?<comment>.*))?\\n")
	#ep input_file
	text.scan(/(?:^\s*\!\s*(?<namelist_comment>[^\n]+))?\n^\&(?<namelist>\S+).*?^\//m) do 
		namelist = $~[:namelist].to_sym
		hash = namelist_hash[namelist] = {}
		#p $~
		scan_text_for_variables($~.to_s).each do |var, val|
			#ep ['Varval', var, val]
			add_code_variable_to_namelist(namelist, var, val) if @strict
			hash[var] =  val
		end
	end
# 	pp namelist_hash
	namelist_hash
end

.parse_old_website_docs(file = ) ⇒ Object



820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
# File 'lib/coderunner/fortran_namelist.rb', line 820

def self.parse_old_website_docs(file = ARGV[-1])
	text = File.read(file)
	text.scan(/Namelist:\s+<i>\s*(?<namelist>\w+).*?<\s*table(?<var_text>(?:<table.*?<\/table>|.)*?)(?=<\/table>)/m) do 
		namelist = $~[:namelist].to_sym
		ep 'namelist', namelist
		var_text = $~[:var_text]
		vars = var_text.split('<tr><th>')
		2.times{vars.shift}
	  vars.each do |var_text|
			ep var_text
			name, type, default, help = var_text.split('<td>')
			name, type, default = [name, type, default].map do |str|
				str.sub(/^\s+/, '').sub(/\s+\Z/, '').gsub(/<[^>]+>/, '')
			end
			name = name.sub(/^\s+/, '').sub(/\s+\Z/, '').gsub(/<[^>]+>/, '').to_sym
			ep 'name', name
			#begin
		  	#p	name, type, help, default, rcp.namelists[namelist][:variables][name][:autoscanned_defaults] 
			#rescue => err
				#p err
				#p namelist, name
			#end
			if rcp.namelists[namelist][:variables][name]
				names = [name]
			else
				names = name.to_s.split(/\s*,\s*/).map{|n| n.to_sym}
			end
			ep 'names', names
			help = help.gsub(/<\/?[bi]>/, '').gsub(/<br>/, '**')
			names.each do |name|
				unless rcp.namelists[namelist][:variables][name]
					var =  rcp.namelists[namelist][:variables].keys.find{|var|  rcp.namelists[namelist][:variables][var][:code_name] == name}
					raise "Can't find #{name.inspect} in #{namelist}" unless var
					name = var
				end

				begin
					sync_variable_help(namelist, name, help)
					if rcp.namelists[namelist][:variables][name][:help] =~ /<[^>]+>/
						edit_variable_help(namelist, name)
					end
				rescue => err
					p namelist, name
					raise err
				end
 
			end 



		end


	end

end

Make a file with doxygen style comments to document the input parameters



1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
# File 'lib/coderunner/fortran_namelist.rb', line 1258

def print_doxygen_documentation
	puts "! This file is not part of GS2, but exists to document those variables which are also input parameters. It is generated automatically by CodeRunner from its input parameter database. To update this database, DO NOT edit this file,  your changes will be lost: go to the wiki page for the input parameters (http://sourceforge.net/apps/mediawiki/gyrokinetics/index.php?title=Gs2_Input_Parameters) and follow the instructions there. \n\n"

	rcp.namelists.each do |nmlist, hash|
		hash[:variables].each do |var, varhash|
			next unless varhash[:module] and varhash[:help]
			puts "module #{varhash[:module]}\n\n\n"
			puts "  #{print_doxygen_variable_documentation(var)}"
			#puts " public :: #{var}"
			puts " #{fortran_type(varhash)} :: #{var}"
			puts "end module #{varhash[:module]}"

		 end
		end
end


1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
# File 'lib/coderunner/fortran_namelist.rb', line 1201

def self.print_doxygen_variable_documentation(variable=ARGV[2])
	#rcp.variables_with_help.each do |var, help|
		#next if var
		#puts var, "\n", help.gsub(/*/, '-'), "\n"
	#end
	#["! <CRDOC #{variable}: CodeRunner generated doc for #{variable}: edit on the wiki!>\n", " !>" + (rcp.variables_with_help[variable.to_sym]||"").gsub(
	[ " !>" + (rcp.variables_with_help[variable.to_sym]||"").gsub(
		/\<math\>/, "\\f$").gsub(
		/\<\/math\>/, "\\f$").gsub(
		/^\s*\*\*/, "  - ").gsub(
		/^\s*\#\#/, "  #- ").gsub(
		/^\s*\#/, '#- ').gsub(
		/^\s*\*/, '- ').gsub(
		/[^\A]^/, "\n  !!")].join(" ")
		#/[^\A]^/, "\n  !!"), "\n  ! </CRDOC #{variable}>"].join(" ")
		#/[^\A]^/, "\n  !!"), "\n  !!- NB, this is automatically generated documentation for an input parameter... see also the wiki page!", "\n  ! </CRDOC #{variable}>"].join(" ")

end

.read_mediawiki_documentation(file = ) ⇒ Object

This reads the mediawiki documentation of the input variables (as generated by write_mediawiki_documentation), copied from a wiki where it has been posted and placed in file, to see if anyone has updated the variable help on the wiki.



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/coderunner/fortran_namelist.rb', line 137

def self.read_mediawiki_documentation(file = ARGV[2])
	documentation = File.read(file)
	#documentation.scan(/^(?<markup>=+)(?<namelist>\w+)\k<markup>(?<vars>.+?)\s+(?=^\k<markup>|\s*\Z)/m) do
	documentation.sub!(/\A.*=Namelists=/m, '')
	documentation.sub!(/\<\/textarea.*\Z/m, '')
	#documentation.scan(/(?<markup>=+)(?<namelist>\w+)\k<markup>(?<vars>.+?)\s+(?=\k<markup>|\|\})/m) do
	documentation.scan(/(?<markup>=+)(?<namelist>\w+)\k<markup>(?<vars>.+?)\s+(?=\|\})/m) do
		p 'nmlist', namelist = $~[:namelist].downcase.to_sym
		vars = $~[:vars]
		p vars
		#vars.scan(/^\*\s*(?:\[\[)?(?<var>\w+)(?:\]\])?\s*:\s+(?<help>.+?)(?=\n\*[^*]|\s*\Z)/m) do
		vars.scan(/\|\-\s+\|'''\[\[\w+\]\]'''\s+\|\|.*?\|\|.*?\|\|\s*?
							(?<var>\w+)
							\s*\|\s*
							\<\!\-\-\s*begin\s+help\s*\-\-\>
													 (?<help>.+?)
													 \<\!\-\-\s*end\s+help\s*\-\-\>
													 /mx) do
			var = $~[:var].downcase.to_sym
			help = $~[:help].sub(/\A\s*\*\s*/, '')
			#p var, help
			sync_variable_help(namelist, var, help) if help.length > 0
		end
	end
end

.save_deleted_variablesObject

Write the list of old variables to the file deleted_variables.rb



386
387
388
# File 'lib/coderunner/fortran_namelist.rb', line 386

def self.save_deleted_variables
	File.open(rcp.code_module_folder + '/deleted_variables.rb', 'w'){|f| f.puts rcp.deleted_variables.pretty_inspect}
end

.save_namelistsObject

Write the namelist database to the file namlists.rb.



381
382
383
# File 'lib/coderunner/fortran_namelist.rb', line 381

def self.save_namelists
	File.open(rcp.code_module_folder + '/namelists.rb', 'w'){|f| f.puts rcp.namelists.pretty_inspect}
end

.scan_text_for_variables(text) ⇒ Object

Scan the text of a namelist from an input file and return an array variables with their default values



560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
# File 'lib/coderunner/fortran_namelist.rb', line 560

def self.scan_text_for_variables(text)
	regex = Regexp.new("#{rcp.matching_regex.to_s}\\s*(?:\\!(?<comment>.*))?[\\n|;]")
	arr = []
	text.scan(regex) do
		match = $~
		var = match[:name].to_sym
		default = match[:default.to_sym]
		default = (match[:float] or match[:complex]) ? match[:default].gsub(/(\.)(\D|$)/, '\10\2').gsub(/[dD]/, 'e').gsub(/(\D|^)(\.)/, '\10\2') : match[:default]
 		#ep 'default', default
		default = eval(default) unless match[:word] or match[:complex]
		default= Complex(*default.scan(LongRegexen::FLOAT).map{|f| f[0].to_f}) if match[:complex]
		arr.push [var, default]
	end
	arr
end

.set_allowed_values(namelist = nil, var, values) ⇒ Object

Sets the allowed values for the variable var in namelist.



392
393
394
395
396
397
398
399
# File 'lib/coderunner/fortran_namelist.rb', line 392

def self.set_allowed_values(namelist=nil, var, values)
	unless namelist
		namelist = rcp.namelists.find{|n, nh| nh[:variables].keys.include? var}[0]
		eputs "Editing namelist #{namelist}"; STDIN.gets
	end
	rcp.namelists[namelist][:variables][var][:allowed_values] = values
	save_namelists
end

.setup_namelists(folder) ⇒ Object

Read the database of namelists and generate the four run class properties

* variables_with_help
* variables_with_autoscanned_defaults
* variables_with_hashes
* variables

The full namelist database itself is assigned to the run class property

* namelists

(Reminder: run class properties are accessed with the rcp call)



36
37
38
39
40
41
42
43
44
45
46
47
48
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
87
88
89
90
91
92
93
94
# File 'lib/coderunner/fortran_namelist.rb', line 36

def self.setup_namelists(folder)
	# 		folder = File.dirname(__FILE__)


		@namelists = eval(File.read(folder + '/namelists.rb'), binding, folder + '/namelists.rb')

		@variables_with_help = (@namelists.inject({}) do |hash, (namelist, namelist_hash)|
			namelist_hash[:variables].each{|var, var_hash| hash[var] = var_hash[:help] if var_hash[:help]}
			hash
		end) 

		@variables_with_autoscanned_defaults = (@namelists.inject({}) do |hash, (namelist, namelist_hash)|
			namelist_hash[:variables].each{|var, var_hash| hash[var] = var_hash[:autoscanned_defaults] if var_hash[:autoscanned_defaults]}
			hash
		end)

		@variables_with_hashes = @namelists.inject({}) do |hash, (namelist, namelist_hash)|
			namelist_hash[:variables].each{|var, var_hash| hash[var] = var_hash unless hash[var] and hash[var][:help]} # If there are duplicates, take the one with help
			hash
		end

	@variables = @namelists.inject([]) do |arr, (namelist, namelist_hash)|
		if en = namelist_hash[:enumerator]
			en[:estimated_value].times do |i|
				namelist_hash[:variables].each{|var, var_hash| arr.push var + "_#{i+1}".to_sym}
			end
		else
			namelist_hash[:variables].each{|var, var_hash| arr.push var}
		end
		arr
	end
	
	@variable_names_from_code_names = @variables_with_hashes.inject({}) do |hash, (var, var_hash)|
		hash[(var_hash[:code_name] || var)] = var
	 	hash
	end
		


	# VARIABLES = VARIABLES_WITH_HELP.keys
	@variables.each{|var| attr_accessor var}

	# Needed for backwards compatibility with old simulation data - variables that
	# are no longer input parameters for the current version of the 
	# simulation code.
	#
	

	begin
		@deleted_variables = eval(File.read(folder + '/deleted_variables.rb'), binding, folder + '/deleted_variables.rb')
	rescue Errno::ENOENT
		@deleted_variables = {}
		save_deleted_variables
	end

	@deleted_variables.keys.each{|var| attr_accessor var}
	

end

.sync_variable_help(namelist, var, help) ⇒ Object

If variable var in the given namelist has no help, add help (a string) to it. If it already has help which is different from help, open an editor to allow the user to resolve the conflict. Requires the environment variable EDITOR to be set.

Raises:

  • (ArgumentError)


251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/coderunner/fortran_namelist.rb', line 251

def self.sync_variable_help(namelist, var, help)
	raise ArgumentError.new("Unknown namelist,variable #{namelist.inspect},#{var.inspect}") unless namelist_hash = rcp.namelists[namelist] and var_hash = namelist_hash[:variables][var]
	if not var_hash[:help] or var_hash[:help] == ""
		var_hash[:help] = help
		save_namelists
		return
	elsif var_hash[:help].sub(/\A\s+/, '').sub(/\s+\Z/, '') == help.sub(/\A\s+/, '').sub(/\s+\Z/, '')
		return
	else
		var_hash[:help] = <<EOF

.<<<<<<<<<<<<current

#{var_hash[:help]}

.>>>>>>>>>>>>new

#{help}
EOF
		edit_variable_help(namelist, var, "Note: There has been a conflict.")
	end
end

.synchronise_variables(source_code_folder = ) ⇒ Object

Find unknown input variables in the source code and add them to the database of namelists Delete input variables which are no longer present in the source code



1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
# File 'lib/coderunner/fortran_namelist.rb', line 1039

def self.synchronise_variables(source_code_folder = ARGV[2])
	source = get_aggregated_source_code_text(source_code_folder)
# 	ep source.size
	nms = {}
	all_variables_in_source = {}
	namelist_declarations = {}
	#source.scan(/^\s*namelist\s*\/(?<namelist>\w+)\/(?<variables>(?:(?:&\s*[\n\r]+)|[^!\n\r])*)/) do 
	source.scan(Regexp.new("#{/^\s*namelist\s*\/(?<namelist>\w+)\//}(?<variables>#{FORTRAN_SINGLE_LINE})")) do 
		namelist = $~[:namelist].to_s.downcase.to_sym
		variables = $~[:variables].gsub(/!.*/, '')
		eputs namelist, variables
		namelist_declarations[namelist] = variables
		#gets # if namelist == :collisions_knobs

		next if [:stuff, :ingen_knobs].include? namelist
		nms[namelist] = []
		all_variables_in_source[namelist] = []
# 		puts variables
		variables.scan(/\w+/) do 
			var =  $~.to_s.to_sym
# 			(p variables, namelist; exit) if var == :following or var == :sou
			all_variables_in_source[namelist].push var
			next if known_code_variable?(namelist, var)
			nms[namelist].push var
		end
		nms[namelist].uniq!
		all_variables_in_source[namelist].uniq!
	end
	variables_to_delete = {}	
	#pp 'namelists', rcp.namelists
	rcp.namelists.each do |namelist, namelist_hash|
		namelist_hash[:variables].each do |variable, var_hash|
			code_variable = var_hash[:code_name] || variable
			unless all_variables_in_source[namelist] and all_variables_in_source[namelist].map{|var| var.to_s.downcase.to_sym}.include? code_variable.to_s.downcase.to_sym
				variables_to_delete[namelist] ||= []
				variables_to_delete[namelist].push variable
			end
		end
	end
	variables_to_delete.each do |namelist, var_array|
		#eputs namelist_declarations[namelist]
		var_array.each do |var|
			p "Namelist: #{namelist}   Variable: #{var}"
		end
	end
	if variables_to_delete.find{|namelist, var_array| var_array.size > 0}
		delete_old = Feedback.get_boolean("These variables are no longer present in the #{rcp.code_long} source folder. Do you wish to delete them?")
		if delete_old
			variables_to_delete.each do |namelist, var_array|
				var_array.each do |var|
					delete_variable(namelist, var)
				end
			end
		end
	end

	eputs nms.keys.zip(nms.values.map{|vs| vs.size})
	eputs "Namelists to be added to. (Press Enter)"; STDIN.gets
	n = 0
# 	ep nms.values.sum
	nms.values.sum.each do |var|
		eputs var if variable_exists? var
	end
	eputs "Conflicting Variables. (Press Enter)";; STDIN.gets
	nms.each do |namelist, vars|
		ep namelist
		ep vars
		vars.each do |var|
# 			next unless var == :w_antenna
			ep var
			values_text = source.scan(Regexp.new("\\W#{var}\\s*=\\s*.+")).join("\n") 
			ep values_text
			values = scan_text_for_variables(values_text).map{|(v,val)| val} 
			values.uniq!
# 			ep values if var == :nbeta
			values.delete_if{|val| val.kind_of? String} if values.find{|val| val.kind_of? Numeric}
			values.delete_if{|val| val.kind_of? String and not String::FORTRAN_BOOLS.include? val} if values.find{|val| val.kind_of? String and String::FORTRAN_BOOLS.include? val}
# 			values.sort!
# 			ep var
# 			ep values
			sample_val = values[0]
			if not values[0] or ( values[0].kind_of? String and not String::FORTRAN_BOOLS.include? values[0])
				p source.scan(Regexp.new("^\s*(?<type>integer|float|character|logical|real|double|complex)(?:&[\\n\\r]|.)*\\W#{var}\\W", Regexp::IGNORECASE)).uniq
				p var unless $~

				case $~[:type]
				when /logical/
					sample_val = '.false.'
				when /int/
					sample_val = 0
				when 'real', 'float', 'double'
					sample_val = 0.0
				when /character/
					sample_val = ""
				when /complex/
					sample_val = Complex(0.0, 0.0)
				end
# 				type = Feedback.get_choice("Found the following possible values for '#{var}' in namelist '#{namelist}': #{values.inspect} but cannot determine its type. Please choose its type", ['Float', 'Integer', 'String', 'Unknown' ])
# 				ep type
				n +=1
				
			end
			p namelist, var, sample_val
			add_code_variable_to_namelist(namelist, var, sample_val)
		end
	end
	ep n
end

.update_defaults_from_source_code(source_code_folder = ) ⇒ Object

This method scans the source code in the given folder and tries to find what value each parameter will be given if the value is not specified in the input file. It is about as subtle as a sledgehammer and doesn’t always find the right answer, but in general is pretty good. The values it finds are stored in the name list hashes as :autoscanned_defaults



973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
# File 'lib/coderunner/fortran_namelist.rb', line 973

def self.update_defaults_from_source_code(source_code_folder = ARGV[-1])
	eputs "Scanning - this takes a while..."
	
# 	[[, File.dirname(__FILE__) + '/namelists.rb']].each do |namelists, file|
	
	namelists = rcp.namelists
# 	file = File.dirname(__FILE__) + '/namelists.rb'
	string = ""
	Dir.chdir(source_code_folder) do 
		namelists.each do |namelist, hash|
			hash[:variables].each do |var, varhash|
				string += `grep -h -E '^[ \t]*#{(varhash[:code_name] or var)}[ \t]*=' *`
				string += `grep -h -E '^[ \t]*#{(varhash[:code_name] or var)}[ \t]*=' */*`
			end
		end
	end
	
# 	string.gsub!(/^.+?:/, '') # Get rid of file names from grep
 File.open('found1','w'){|f| f.puts string}
#  exit
	defs = scan_text_for_variables(string) 
	File.open('found2','w'){|f| f.puts defs.pretty_inspect}
# 	exit
	namelists.each do |namelist, hash|
		hash[:variables].each do |var, varhash|
			p var if var == :nwrite
			values = defs.find_all{|(v, df)| v == (varhash[:code_name] or var)}.map{|(v,df)| df}
			values.uniq!
			p values if var == :nwrite
			values.delete_if{|val| val.kind_of? String} if values.find{|val| val.kind_of? Numeric}
			p values if var == :nwrite
			values.delete_if{|val| val.kind_of? String and not String::FORTRAN_BOOLS.include? val} if values.find{|val| val.kind_of? String and String::FORTRAN_BOOLS.include? val}
			p values if var == :nwrite
			values.sort!
			hash[:variables][var][:autoscanned_defaults] = values
# 			ep var, values
		end
	end
	save_namelists
# 	File.open(file, 'w'){|f| f.puts namelists.pretty_inspect}
# 	end
end

.update_folder_defaultsObject

This method doesn’t quite work. It is supposed to edit a local copy of a defaults file and update it to reflect any changes made to the central defaults file, without overriding any changes made to the local defaults file.



695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
# File 'lib/coderunner/fortran_namelist.rb', line 695

def self.update_folder_defaults #updates the defaults file in the current folder to add any new defaults settings from the given modlet. Does NOT change exist settings
	current =  File.read((defaults_file = rcp.modlet + '_defaults.rb'))
	updated = File.read("#{rcp.modlet_location}/#{defaults_file}")
	hash = current.scan(/(^\s*\@(\w+).*)/).inject({}) do |hash, (all, name)|
		hash[name] = all unless name.to_s =~ /iphi00/
		hash
	end
# 	new_hash = {}
	updated.scan(/(^\s*\@(\w+).*)/).each do |all, name|
		next if name.to_s =~ /iphi00/
		unless SPECIES_DEPENDENT_VARIABLES.include? name.sub(/_\d+$/, '').to_sym
			hash[name] = all unless hash[name]
		else
# 			puts name
			name.sub(/_1$/, '')
			if hash[name.sub(/_1$/, '_i').sub(/_2$/, '_e')]
				hash[name] = hash[name.sub(/_1$/, '_i').sub(/_2$/, '_e')].sub(/_i\b/, '_1').sub(/_e\b/, '_2')
				hash.delete(name.sub(/_1$/, '_i').sub(/_2$/, '_e'))
			elsif hash[name.sub(/_1$/, '')]
				ep name
				hash[name] = hash[name.sub(/_1$/, '')].sub(/(^\@\w+)/, '\1_1')
				hash.delete(name.sub(/_1$/, ''))
			else
				hash[name] = all
			end
		end
	end
# 	eputs hash.pretty_inspect
# 	puts hash.values
	hash['adiabatic_option'] ||= %[@adiabatic_option = "iphi00=2"]
	puts hash.values

	# 	File.open(defaults_file, 'w'){|file| file.puts hash.values}

end

.update_text_options(source_code_folder = ) ⇒ Object



1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
# File 'lib/coderunner/fortran_namelist.rb', line 1161

def self.update_text_options(source_code_folder = ARGV[-1])
	source = get_aggregated_source_code_text(source_code_folder)
	options = {}
	source.scan(/^\s*type\s*\(text_option\)\s*.*?\:\:\s*(?<var>\w+)\s+(?<options>(?:(?:&\s*[\n\r]+)|(?:\s*!.*[\n\r])|[^!\n\r])*)/) do 
			
                         name = $~[:var]
# 			 eputs $~ if name == "adiabaticopts"
			 opts =  $~[:options].scan(/text_option\('([^']+)/).flatten
			 name = "collision_model_opts" if opts.include? "krook" 
			 options[name] = opts
	end
	mapping = {}
# 	get_option_value &
#          (ginit_option, ginitopts, ginitopt_switch, &
	source.scan(/^\s*call\s*get_option_value[\s|&]*\((?<var>\w+),[\s|&]*(?<options>\w+)/) do 
#                          p $~
			 var = $~[:var].to_sym
			 op = $~[:options]
			op = "collision_model_opts" if var == :collision_model
			 mapping[var] = op
	end
# 	pp mapping
# 	pp options
# 	string_vars = []
	rcp.namelists.each do |namelist, nhash|
		nhash[:variables].each do |var, varhash|
			if varhash[:type] == :String
				if mapping[(varhash[:code_name] or var)]
					varhash[:text_options] = options[mapping[var]].uniq
# 					pp var, varhash
				end
				
			end
		end
	end
	save_namelists
# 	ep options, string_vars, mapping
# 	File.open(File.dirname(__FILE__) + '/namelists.rb', 'w'){|f| f.puts NAMELISTS.pretty_inspect}
end

.variable_exists?(namelist = nil, var) ⇒ Boolean

Does the variable var exist? If it does exist, returns a list of the namelists in which it is found. Otherwise returns false

Returns:

  • (Boolean)


100
101
102
103
104
105
106
# File 'lib/coderunner/fortran_namelist.rb', line 100

def self.variable_exists?(namelist=nil, var)
	exists = false
		#exists = rcp.namelists.find_all{|namelist, hash| hash[:variables].keys.map{|v| v.to_s.downcase.to_sym}.include? var.to_s.downcase.to_sym}
		exists = rcp.namelists.find_all{|namelist, hash| hash[:variables].keys.include? var}
# 	end
	return exists.size > 0 ? exists.map{|(namelist, hash)| namelist} : false
end

.write_mediawiki_documentationObject

This method takes the help written into this module for the various input parameters and writes it in a format suitable for the mediawiki page on input parameters.



879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
# File 'lib/coderunner/fortran_namelist.rb', line 879

def self.write_mediawiki_documentation
	puts <<EOF
=Introduction=

This page lists every GS2 input parameter currently known about, along with any help available. It is intended as a reference, not an introduction. Note: some parameters are highly specialised and not intended for general use.

A full introduction to writing input files is to be written, but until then, this is an old example input file. Be aware that not every section should be included.

[[GS2 Reference Input File]]

==Format==

The parameters are divided into namelists. Each parameter has type information and written help where available. The format is:

{| border="2" cellpadding="5"
! Name !! Type !! Def !! CR Name !! Description 
|-
|-
|Name as it appears in GS2 ||  Fortran Data Type ||  Autoscanned Default(s): guesses at what the default value of this parameter will be if you do not specify it in the input file. They are usually correct.
|| CodeRunner Name: is the variable name used by [http://coderunner.sourceforge.net CodeRunner] to refer to the quantity (only given if it is different to the GS2 name). 
|
Long and detailed help for the variable
|}


==Updating this Page==

This page is automatically generated by [http://coderunner.sourceforge.net CodeRunner], but any '''changes you make will be kept''', so please feel free to contribute. Please keep to the same format as this allows easy automatic syncing of your changes with the CodeRunner database. '''Please only edit in between the <nowiki><!-- begin help --> <!-- end help --> </nowiki> or the <nowiki><!-- begin namelist help --> <!-- end namelist help --> </nowiki>  tags'''. Don't edit type/default information (or this introduction) as it will not be kept.

=Namelists=

Each GS2 module is controlled by its own namelist. For typical applications, not all 32+ namelists should appear in a single file. For a run called runname, this file should be called <tt>runname.in</tt>. In most cases, defaults are loaded for each namelist element, so that if a namelist or  element does not appear, the run will not automatically stop. (It may still be forced to stop if the defaults are incompatible with your other choices.) The namelists and defaults appear below.
EOF

	rcp.namelists.each do |namelist, hash|
		puts "==#{namelist}=="
		puts "<!--begin namelist help-->#{hash[:help]}<!--end namelist help-->"
		puts "\n{| border=\"2\" cellpadding=\"5\"\n! Name !! Type !! Def !! CR Name !! Description \n|-"
		hash[:variables].keys.sort.each do |var|
			var_hash = hash[:variables][var]
			#puts "==='''[[#{(var_hash[:code_name] or var)}]]'''==="
			puts "|-\n|'''[[#{(var_hash[:code_name] or var)}]]''' ||  #{var_hash[:type]} ||  #{(var_hash[:autoscanned_defaults]||[]).map{|v| v.to_s}.join(",")} || #{var} \n|\n<!--begin help-->*  #{hash[:variables][var][:help]} <!-- end help -->"
			#puts "''Type'': #{var_hash[:type]} "
			#puts "''Autoscanned Defaults'': #{var_hash[:autoscanned_defaults]} "
			#puts "''CodeRunner name'': #{var} "
	  #puts "\n", "#{hash[:variables][var][:help]}".sub(/\A\s+/, '') if hash[:variables][var][:help]
			#puts " #{(var_hash[:code_name] or var)} Properties:"
		end
		puts "|}"
	end
end

Instance Method Details

#input_file_textObject

Generate input file text using the namelists, the values of the run instance variables and the customised method input_file_header.



582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
# File 'lib/coderunner/fortran_namelist.rb', line 582

def input_file_text
	text = input_file_header
	rcp.namelists.each do |namelist, hash|
		next if hash[:should_include].kind_of? String and not eval(hash[:should_include])
		if en = hash[:enumerator] # Single = is deliberate!
			next unless send(en[:name])
			send(en[:name]).times do |i|
				next unless hash[:variables].keys.inject(false){|b, v| b or !send(v+"_#{i+1}".to_sym).nil?} # i.e. at least one variable must be non-nil 
				text << namelist_text(namelist, i+1)
			end
		else
			next unless hash[:variables].keys.inject(false){|b, v| b or !send(v).nil?} # i.e. at least one variable must be non-nil 
			text << namelist_text(namelist)
		end
			
			
	end
	text
end

#make_info_file(file = , strict = true) ⇒ Object

This method takes an input file and generates a CodeRunner info file. It should not be called in a folder where a CodeRunner info file already exists, as it will overwrite that info file with a less complete one.



787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
# File 'lib/coderunner/fortran_namelist.rb', line 787

def make_info_file(file=ARGV[-1], strict=true)
	hash = self.class.parse_input_file(file, strict)
# 	species_dependent_namelists = SPECIES_DEPENDENT_NAMELISTS.keys
	filename = File.dirname(file) + '/code_runner_info.rb'
# 		(puts "Warning: An info file exists: if you continue it will be overwritten, and the original may contain more information. Press enter to continue, Crtl + C to cancel"; gets) if FileTest.exist? filename
	
# 		pp hash, species_dependent_namelists
# 		run= new(@@runner)
	hash.each do |namelist, vars|
		num  = nil
# 		ep namelist
		namelist = namelist.to_s.sub(/\_(?<num>\d+)$/, '').to_sym
		if $~  # I.e if there was a number at the end of the namelist
# 			ep namelist
			raise "This namelist: #{namelist} should have an enumerator and does not have one" if not rcp.namelists[namelist][:enumerator]
			num = $~[:num]
		end
		vars.each do |var, value|
			#ep 'var', var
			var = (rcp.variable_names_from_code_names[var.to_sym] + (num ? "_#{num}" : "")).to_sym
# 				p var, value
			set(var, value)
		end
		set(:run_name, file.sub(/\.in/, ''))
# 		p 'hello'
		File.open(filename, 'w'){|file| file.puts info_file}	
		File.open(".code_runner_version.txt", 'w'){|file| file.puts CODE_RUNNER_VERSION}
	end
# 	end
# 		ep @@variables
	
end

#namelist_text(namelist, enum = nil) ⇒ Object

Generate the input file text for the given namelist. Called by input_file_text.



604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
# File 'lib/coderunner/fortran_namelist.rb', line 604

def namelist_text(namelist, enum = nil)
	hash = rcp.namelists[namelist]
	text = ""
	ext = enum ? "_#{enum}" : ""
	text << "!#{'='*30}\n!#{hash[:description]} #{enum} \n!#{'='*30}\n" if hash[:description]
	text << "&#{namelist}#{ext}\n"
	hash[:variables].each do |var, var_hash|
		code_var = (var_hash[:code_name] or var)
		cr_var = var+ext.to_sym 
		if send(cr_var) and (not var_hash[:should_include] or  eval(var_hash[:should_include]))
			if String::FORTRAN_BOOLS.include? send(cr_var) # var is a Fortran Bool, not really a string
				output = send(cr_var).to_s
			elsif (v = send(cr_var)).kind_of? Complex
				output = "(#{v.real}, #{v.imag})"
			else
				#p cr_var, cr_var.class
				output = send(cr_var).inspect
			end
			text << " #{code_var} = #{output} #{var_hash[:description] ? "! #{var_hash[:description]}": ""}\n"
		end
	end
	text << "/\n\n"
	text
end