Class: CodeRunner::Run::FortranNamelist
- Inherits:
-
CodeRunner::Run
- Object
- CodeRunner::Run
- CodeRunner::Run::FortranNamelist
- 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 =
/(?: (?:&[ \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
-
.add_code_variable_to_namelist(namelist, var, value) ⇒ Object
Add variable
var
, with a sample value, tonamelist
in the database of namelists. -
.add_help_to_variable(namelist = , var = , help = ) ⇒ Object
Add help to the variable in the given namelist.
-
.add_namelist_must_pass(namelist, tst) ⇒ Object
Add a test which the namelist must pass before being included in the input file.
-
.add_namelist_should_pass(namelist, tst) ⇒ Object
Add a test which the namelist should pass before being included in the input file.
-
.add_variable_must_pass(namelist = nil, var, tst) ⇒ Object
Add a test which the variable must pass before being included in the input file.
-
.add_variable_should_pass(namelist = nil, var, tst) ⇒ Object
Add a test which the variable should pass before being included in the input file.
-
.correct_namelist_cases ⇒ Object
For backward compatibility: ensures that all variables (NB variables, not code_variables) are lower case in the namelist database.
-
.correct_type_location ⇒ Object
A one off function designed to correct an old error in the namelists.
- .defaults_file_text_from_input_file(input_file) ⇒ Object
-
.delete_variable(namelist, var) ⇒ Object
Deletes the given variable from the namelists and saves the namelists.
-
.diff_input_files(file1 = , file2 = ) ⇒ Object
This method compares two different input files and prints out a hash summarising the differences between them.
-
.edit_namelist_help(namelist, message = "") ⇒ Object
Edit the help for the namelist.
-
.edit_variable_help(namelist, var, message = "") ⇒ Object
Edit the help for the variable in var in the given namelist.
-
.find_variable_hash(var) ⇒ Object
Return the hash of variable properties if it exists.
- .fortran_type(varhash) ⇒ Object
-
.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.
-
.get_variable_modules(folder = ) ⇒ Object
(also: gvm)
Work out which module a variable is found in.
-
.help_input(var = ARGV[2].to_sym) ⇒ Object
Print help for the given variable to STDOUT.
-
.help_variables ⇒ Object
Print out a list of every variable with help attached.
-
.known_code_variable?(namelist, var) ⇒ Boolean
Returns true if the code variable (which may correspond to the code name) is present in namelist.
-
.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.
-
.namelist_defaults_text(hash, namelist, namelist_hash, enum = nil) ⇒ Object
Called by defaults_file_text_from_input_file.
-
.parse_input_file(input_file, strict = true) ⇒ Object
(also: generate_simple_namelist_hash)
Parses a Fortran namelist input file into a hash of { :namelist => { :variable => value } }.
- .parse_old_website_docs(file = ) ⇒ Object
-
.print_doxygen_documentation ⇒ Object
(also: pdd)
Make a file with doxygen style comments to document the input parameters.
- .print_doxygen_variable_documentation(variable = ) ⇒ Object (also: pdvd)
-
.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. -
.save_deleted_variables ⇒ Object
Write the list of old variables to the file deleted_variables.rb.
-
.save_namelists ⇒ Object
Write the namelist database to the file namlists.rb.
-
.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.
-
.set_allowed_values(namelist = nil, var, values) ⇒ Object
Sets the allowed values for the variable
var
innamelist
. -
.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.
-
.sync_variable_help(namelist, var, help) ⇒ Object
If variable var in the given namelist has no help, add
help
(a string) to it. -
.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.
-
.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.
-
.update_folder_defaults ⇒ Object
This method doesn’t quite work.
- .update_text_options(source_code_folder = ) ⇒ Object
-
.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.
-
.write_mediawiki_documentation ⇒ Object
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.
Instance Method Summary collapse
-
#input_file_text ⇒ Object
Generate input file text using the namelists, the values of the run instance variables and the customised method
input_file_header
. -
#make_info_file(file = , strict = true) ⇒ Object
This method takes an input file and generates a CodeRunner info file.
-
#namelist_text(namelist, enum = nil) ⇒ Object
Generate the input file text for the given namelist.
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_cases ⇒ Object
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_location ⇒ Object
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.
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, = "") 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. #{} -------------------------------------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.
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, = "") 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. #{} -------------------------------------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_variables ⇒ Object
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
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 |
.print_doxygen_documentation ⇒ Object Also known as: pdd
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 |
.print_doxygen_variable_documentation(variable = ) ⇒ Object Also known as: pdvd
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_variables ⇒ Object
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_namelists ⇒ Object
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.
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_defaults ⇒ Object
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.(source_code_folder = ARGV[-1]) source = get_aggregated_source_code_text(source_code_folder) = {} 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" [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] = [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
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_documentation ⇒ Object
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_text ⇒ Object
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 |