gs2crmod 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +20 -0
- data/README.md +4 -0
- data/README.rdoc +19 -0
- data/Rakefile +56 -0
- data/VERSION +1 -0
- data/ext/extconf.rb +9 -0
- data/ext/gs2crmod_ext.c +366 -0
- data/gs2crmod.gemspec +98 -0
- data/include/gs2crmod_ext.h +58 -0
- data/lib/gs2crmod/astrogk/astrogk.rb +201 -0
- data/lib/gs2crmod/astrogk/calculations.rb +57 -0
- data/lib/gs2crmod/astrogk/check_convergence.rb +7 -0
- data/lib/gs2crmod/astrogk/deleted_variables.rb +76 -0
- data/lib/gs2crmod/astrogk/graphs.rb +13 -0
- data/lib/gs2crmod/astrogk/gsl_data.rb +13 -0
- data/lib/gs2crmod/astrogk/gsl_tools.rb +182 -0
- data/lib/gs2crmod/astrogk/ingen.rb +18 -0
- data/lib/gs2crmod/astrogk/input_file_tools.rb +7 -0
- data/lib/gs2crmod/astrogk/namelist_tools.rb +14 -0
- data/lib/gs2crmod/astrogk/namelists.rb +2800 -0
- data/lib/gs2crmod/astrogk/properties.rb +17 -0
- data/lib/gs2crmod/astrogk/species_dependent_namelists.rb +228 -0
- data/lib/gs2crmod/astrogk/test_gs2.rb +231 -0
- data/lib/gs2crmod/astrogk.rb +200 -0
- data/lib/gs2crmod/calculations.rb +780 -0
- data/lib/gs2crmod/check_convergence.rb +179 -0
- data/lib/gs2crmod/deleted_variables.rb +916 -0
- data/lib/gs2crmod/graphs.rb +1899 -0
- data/lib/gs2crmod/graphs_rdoc.rb +556 -0
- data/lib/gs2crmod/gs2.rb +1143 -0
- data/lib/gs2crmod/gsl_data.rb +1181 -0
- data/lib/gs2crmod/gsl_data_3d.rb +705 -0
- data/lib/gs2crmod/gsl_tools.rb +187 -0
- data/lib/gs2crmod/ingen.rb +218 -0
- data/lib/gs2crmod/namelists.rb +5142 -0
- data/lib/gs2crmod/properties.rb +22 -0
- data/lib/gs2crmod/species_dependent_namelists.rb +228 -0
- data/lib/gs2crmod/test_gs2.rb +231 -0
- data/lib/gs2crmod.rb +2 -0
- data/lib/gs2crmod_extension.rb +1 -0
- data/test/helper.rb +18 -0
- data/test/test_gs2crmod.rb +7 -0
- metadata +176 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
class CodeRunner
|
2
|
+
class Gs2::Astrogk
|
3
|
+
|
4
|
+
|
5
|
+
######################################
|
6
|
+
# GS2 CodeRunner Module
|
7
|
+
#
|
8
|
+
# Calculated Properties
|
9
|
+
#
|
10
|
+
# These are methods which calculate
|
11
|
+
# miscellaneous properties of the run.
|
12
|
+
#
|
13
|
+
#####################################
|
14
|
+
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,228 @@
|
|
1
|
+
{:species_parameters=>
|
2
|
+
{:description=>"SPECIES ",
|
3
|
+
:include_conditions=>"true",
|
4
|
+
:variables=>
|
5
|
+
{:z=>
|
6
|
+
{:help=>"Charge",
|
7
|
+
:include_conditions=>"true",
|
8
|
+
:description=>"Charge",
|
9
|
+
:tests=>["Tst::FLOAT"],
|
10
|
+
:autoscanned_defaults=>[],
|
11
|
+
:must_pass=>
|
12
|
+
[{:test=>"kind_of? Numeric",
|
13
|
+
:explanation=>
|
14
|
+
"This variable must be a floating point number (an integer is also acceptable: it will be converted into a floating point number)."}]},
|
15
|
+
:mass=>
|
16
|
+
{:help=>"Mass",
|
17
|
+
:include_conditions=>"true",
|
18
|
+
:description=>"Mass",
|
19
|
+
:tests=>["Tst::FLOAT"],
|
20
|
+
:autoscanned_defaults=>[],
|
21
|
+
:must_pass=>
|
22
|
+
[{:test=>"kind_of? Numeric",
|
23
|
+
:explanation=>
|
24
|
+
"This variable must be a floating point number (an integer is also acceptable: it will be converted into a floating point number)."}]},
|
25
|
+
:dens=>
|
26
|
+
{:help=>"Density\t",
|
27
|
+
:include_conditions=>"true",
|
28
|
+
:description=>"Density\t",
|
29
|
+
:tests=>["Tst::FLOAT"],
|
30
|
+
:autoscanned_defaults=>[],
|
31
|
+
:must_pass=>
|
32
|
+
[{:test=>"kind_of? Numeric",
|
33
|
+
:explanation=>
|
34
|
+
"This variable must be a floating point number (an integer is also acceptable: it will be converted into a floating point number)."}]},
|
35
|
+
:temp=>
|
36
|
+
{:help=>"Temperature",
|
37
|
+
:include_conditions=>"true",
|
38
|
+
:description=>"Temperature",
|
39
|
+
:tests=>["Tst::FLOAT"],
|
40
|
+
:autoscanned_defaults=>[],
|
41
|
+
:must_pass=>
|
42
|
+
[{:test=>"kind_of? Numeric",
|
43
|
+
:explanation=>
|
44
|
+
"This variable must be a floating point number (an integer is also acceptable: it will be converted into a floating point number)."}]},
|
45
|
+
:tprim=>
|
46
|
+
{:help=>"6.0 !-1/T (dT/drho)",
|
47
|
+
:include_conditions=>"true",
|
48
|
+
:description=>"6.0 !-1/T (dT/drho)",
|
49
|
+
:tests=>["Tst::FLOAT"],
|
50
|
+
:autoscanned_defaults=>[],
|
51
|
+
:must_pass=>
|
52
|
+
[{:test=>"kind_of? Numeric",
|
53
|
+
:explanation=>
|
54
|
+
"This variable must be a floating point number (an integer is also acceptable: it will be converted into a floating point number)."}]},
|
55
|
+
:fprim=>
|
56
|
+
{:help=>"2.22 !-1/n (dn/drho)",
|
57
|
+
:include_conditions=>"true",
|
58
|
+
:description=>"2.22 !-1/n (dn/drho)",
|
59
|
+
:tests=>["Tst::FLOAT"],
|
60
|
+
:autoscanned_defaults=>[],
|
61
|
+
:must_pass=>
|
62
|
+
[{:test=>"kind_of? Numeric",
|
63
|
+
:explanation=>
|
64
|
+
"This variable must be a floating point number (an integer is also acceptable: it will be converted into a floating point number)."}]},
|
65
|
+
:uprim=>
|
66
|
+
{:help=>"?",
|
67
|
+
:include_conditions=>"true",
|
68
|
+
:description=>"?",
|
69
|
+
:tests=>["Tst::FLOAT"],
|
70
|
+
:autoscanned_defaults=>[],
|
71
|
+
:must_pass=>
|
72
|
+
[{:test=>"kind_of? Numeric",
|
73
|
+
:explanation=>
|
74
|
+
"This variable must be a floating point number (an integer is also acceptable: it will be converted into a floating point number)."}]},
|
75
|
+
:vnewk=>
|
76
|
+
{:help=>"1.e-2 !collisionality parameter",
|
77
|
+
:include_conditions=>"true",
|
78
|
+
:description=>"1.e-2 !collisionality parameter",
|
79
|
+
:tests=>["Tst::FLOAT"],
|
80
|
+
:autoscanned_defaults=>[],
|
81
|
+
:must_pass=>
|
82
|
+
[{:test=>"kind_of? Numeric",
|
83
|
+
:explanation=>
|
84
|
+
"This variable must be a floating point number (an integer is also acceptable: it will be converted into a floating point number)."}]},
|
85
|
+
:type=>
|
86
|
+
{:help=>"'ion' Thermal ion species ",
|
87
|
+
:include_conditions=>"true",
|
88
|
+
:description=>"'ion' Thermal ion species ",
|
89
|
+
:tests=>["Tst::STRING"],
|
90
|
+
:autoscanned_defaults=>[],
|
91
|
+
:must_pass=>
|
92
|
+
[{:test=>"kind_of? String",
|
93
|
+
:explanation=>"This variable must be a string."}]},
|
94
|
+
:dens0=>
|
95
|
+
{:should_include=>"true",
|
96
|
+
:description=>nil,
|
97
|
+
:help=>nil,
|
98
|
+
:tests=>["Tst::FLOAT"],
|
99
|
+
:gs2_name=>:dens0,
|
100
|
+
:must_pass=>
|
101
|
+
{:test=>"kind_of? Numeric",
|
102
|
+
:explanation=>
|
103
|
+
"This variable must be a floating point number (an integer is also acceptable: it will be converted into a floating point number)."},
|
104
|
+
:autoscanned_defaults=>[1.0]},
|
105
|
+
:u0=>
|
106
|
+
{:should_include=>"true",
|
107
|
+
:description=>nil,
|
108
|
+
:help=>nil,
|
109
|
+
:tests=>["Tst::FLOAT"],
|
110
|
+
:gs2_name=>:u0,
|
111
|
+
:must_pass=>
|
112
|
+
{:test=>"kind_of? Numeric",
|
113
|
+
:explanation=>
|
114
|
+
"This variable must be a floating point number (an integer is also acceptable: it will be converted into a floating point number)."},
|
115
|
+
:autoscanned_defaults=>[1.0]},
|
116
|
+
:uprim2=>
|
117
|
+
{:should_include=>"true",
|
118
|
+
:description=>nil,
|
119
|
+
:help=>nil,
|
120
|
+
:tests=>["Tst::FLOAT"],
|
121
|
+
:gs2_name=>:uprim2,
|
122
|
+
:must_pass=>
|
123
|
+
{:test=>"kind_of? Numeric",
|
124
|
+
:explanation=>
|
125
|
+
"This variable must be a floating point number (an integer is also acceptable: it will be converted into a floating point number)."},
|
126
|
+
:autoscanned_defaults=>[0.0]},
|
127
|
+
:nustar=>
|
128
|
+
{:should_include=>"true",
|
129
|
+
:description=>nil,
|
130
|
+
:help=>nil,
|
131
|
+
:tests=>["Tst::FLOAT"],
|
132
|
+
:gs2_name=>:nustar,
|
133
|
+
:must_pass=>
|
134
|
+
{:test=>"kind_of? Numeric",
|
135
|
+
:explanation=>
|
136
|
+
"This variable must be a floating point number (an integer is also acceptable: it will be converted into a floating point number)."},
|
137
|
+
:autoscanned_defaults=>[-1.0]},
|
138
|
+
:nu=>
|
139
|
+
{:should_include=>"true",
|
140
|
+
:description=>nil,
|
141
|
+
:help=>nil,
|
142
|
+
:tests=>["Tst::FLOAT"],
|
143
|
+
:gs2_name=>:nu,
|
144
|
+
:must_pass=>
|
145
|
+
{:test=>"kind_of? Numeric",
|
146
|
+
:explanation=>
|
147
|
+
"This variable must be a floating point number (an integer is also acceptable: it will be converted into a floating point number)."},
|
148
|
+
:autoscanned_defaults=>[-1.0]},
|
149
|
+
:nu_h=>
|
150
|
+
{:should_include=>"true",
|
151
|
+
:description=>nil,
|
152
|
+
:help=>nil,
|
153
|
+
:tests=>["Tst::FLOAT"],
|
154
|
+
:gs2_name=>:nu_h,
|
155
|
+
:must_pass=>
|
156
|
+
{:test=>"kind_of? Numeric",
|
157
|
+
:explanation=>
|
158
|
+
"This variable must be a floating point number (an integer is also acceptable: it will be converted into a floating point number)."},
|
159
|
+
:autoscanned_defaults=>[0.0]},
|
160
|
+
:tperp0=>
|
161
|
+
{:should_include=>"true",
|
162
|
+
:description=>nil,
|
163
|
+
:help=>nil,
|
164
|
+
:tests=>["Tst::FLOAT"],
|
165
|
+
:gs2_name=>:tperp0,
|
166
|
+
:must_pass=>
|
167
|
+
{:test=>"kind_of? Numeric",
|
168
|
+
:explanation=>
|
169
|
+
"This variable must be a floating point number (an integer is also acceptable: it will be converted into a floating point number)."},
|
170
|
+
:autoscanned_defaults=>[0.0]},
|
171
|
+
:tpar0=>
|
172
|
+
{:should_include=>"true",
|
173
|
+
:description=>nil,
|
174
|
+
:help=>nil,
|
175
|
+
:tests=>["Tst::FLOAT"],
|
176
|
+
:gs2_name=>:tpar0,
|
177
|
+
:must_pass=>
|
178
|
+
{:test=>"kind_of? Numeric",
|
179
|
+
:explanation=>
|
180
|
+
"This variable must be a floating point number (an integer is also acceptable: it will be converted into a floating point number)."},
|
181
|
+
:autoscanned_defaults=>[0.0]}}},
|
182
|
+
:dist_fn_species_knobs=>
|
183
|
+
{:description=>"",
|
184
|
+
:include_conditions=>"true",
|
185
|
+
:variables=>
|
186
|
+
{:fexpr=>
|
187
|
+
{:help=>
|
188
|
+
"0.5 !Temporal implicitness parameter. Recommended value: 0.48",
|
189
|
+
:include_conditions=>"true",
|
190
|
+
:description=>
|
191
|
+
"0.5 !Temporal implicitness parameter. Recommended value: 0.48",
|
192
|
+
:tests=>["Tst::FLOAT"],
|
193
|
+
:autoscanned_defaults=>[],
|
194
|
+
:must_pass=>
|
195
|
+
[{:test=>"kind_of? Numeric",
|
196
|
+
:explanation=>
|
197
|
+
"This variable must be a floating point number (an integer is also acceptable: it will be converted into a floating point number)."}]},
|
198
|
+
:fexpi=>
|
199
|
+
{:help=>nil,
|
200
|
+
:include_conditions=>"true",
|
201
|
+
:description=>nil,
|
202
|
+
:tests=>["Tst::FLOAT"],
|
203
|
+
:autoscanned_defaults=>[],
|
204
|
+
:must_pass=>
|
205
|
+
[{:test=>"kind_of? Numeric",
|
206
|
+
:explanation=>
|
207
|
+
"This variable must be a floating point number (an integer is also acceptable: it will be converted into a floating point number)."}]},
|
208
|
+
:bakdif=>
|
209
|
+
{:help=>"0.0 !Spatial implicitness parameter. Recommended value: 0.05",
|
210
|
+
:include_conditions=>"true",
|
211
|
+
:description=>
|
212
|
+
"0.0 !Spatial implicitness parameter. Recommended value: 0.05",
|
213
|
+
:tests=>["Tst::FLOAT"],
|
214
|
+
:autoscanned_defaults=>[],
|
215
|
+
:must_pass=>
|
216
|
+
[{:test=>"kind_of? Numeric",
|
217
|
+
:explanation=>
|
218
|
+
"This variable must be a floating point number (an integer is also acceptable: it will be converted into a floating point number)."}]},
|
219
|
+
:bd_exp=>
|
220
|
+
{:should_include=>"true",
|
221
|
+
:description=>nil,
|
222
|
+
:help=>nil,
|
223
|
+
:tests=>["Tst::INT"],
|
224
|
+
:gs2_name=>:bd_exp,
|
225
|
+
:must_pass=>
|
226
|
+
{:test=>"kind_of? Integer",
|
227
|
+
:explanation=>"This variable must be an integer."},
|
228
|
+
:autoscanned_defaults=>["bd_exp_out"]}}}}
|
@@ -0,0 +1,231 @@
|
|
1
|
+
class CodeRunner
|
2
|
+
class Gs2::Astrogk
|
3
|
+
|
4
|
+
# See TestAstrogk
|
5
|
+
|
6
|
+
def self.test_gs2(*args)
|
7
|
+
TestAstrogk.test_gs2(*args)
|
8
|
+
end
|
9
|
+
|
10
|
+
# = Astrogk Test Suite
|
11
|
+
# This class is designed to run a set of functional tests to test the GS2 source. It is not a test suite for GS2crmod, the GS2 CodeRunner module. It takes all the input files from the folder <tt>test_cases</tt>, runs them and checks that they give the same output as the standard case. Only the NetCDF file from the standard case should be included, and should have the same name as the test case input file.
|
12
|
+
|
13
|
+
module TestAstrogk
|
14
|
+
|
15
|
+
|
16
|
+
# The folder where all the test files are stored.
|
17
|
+
|
18
|
+
TEST_FOLDER = Dir.pwd #File.dirname(__FILE__) + "../test_cases"
|
19
|
+
|
20
|
+
|
21
|
+
# Give the standardised name of the test_results folder, given the name of the test case input file
|
22
|
+
|
23
|
+
def self.results_folder(input_file)
|
24
|
+
'test_results/' + input_file.sub(/\.in$/, '')
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.test_case_folder(input_file)
|
28
|
+
TEST_FOLDER + '/' + input_file.sub(/\.in$/, '')
|
29
|
+
end
|
30
|
+
|
31
|
+
# The io object all test info is written to.
|
32
|
+
|
33
|
+
TEST_OUT = STDERR
|
34
|
+
|
35
|
+
# Run all the test cases. test_case_location should be the folder test_cases in the gs2 source.
|
36
|
+
#
|
37
|
+
# Options are
|
38
|
+
# * restart (default: true) Delete all results and start again.
|
39
|
+
# * submit (default: true) Submit any runs that haven't been submitted.
|
40
|
+
# * serial (default: true) Wait till one test run has finished before starting another
|
41
|
+
|
42
|
+
def self.test_gs2(test_case_location, options={})
|
43
|
+
Astrogk.send(:include, self)
|
44
|
+
test_case_location.sub!(/~/, ENV['HOME'])
|
45
|
+
TEST_FOLDER.gsub!(/^.*$/, test_case_location)
|
46
|
+
raise "The first argument should be the test_cases folder" unless File.basename(TEST_FOLDER) == "test_cases"
|
47
|
+
@tests_failed = {}
|
48
|
+
|
49
|
+
|
50
|
+
serial = true unless ["false", false].include? options[:serial]
|
51
|
+
restart = true unless ["false", false].include? options[:restart]
|
52
|
+
submit = true unless ["false", false].include? options[:submit]
|
53
|
+
|
54
|
+
|
55
|
+
@test_runner = CodeRunner.fetch_runner(Y: Dir.pwd, u: true)
|
56
|
+
@submitted_tests = @test_runner.runs.map{|run| run.run_name}
|
57
|
+
test_cases = Dir.entries(TEST_FOLDER).find_all do |entry|
|
58
|
+
# p entry
|
59
|
+
File.directory?(TEST_FOLDER + '/' + entry) and not entry =~ /^\./
|
60
|
+
end
|
61
|
+
# p test_cases
|
62
|
+
|
63
|
+
if restart
|
64
|
+
FileUtils.rm_r 'test_results' if FileTest.exist? 'test_results'
|
65
|
+
FileUtils.makedirs 'test_results'
|
66
|
+
end
|
67
|
+
|
68
|
+
# Submit the tests
|
69
|
+
if submit
|
70
|
+
test_cases.each do |test_case|
|
71
|
+
next if FileTest.exist? results_folder(test_case)
|
72
|
+
submit_run(test_case)
|
73
|
+
run_tests if serial
|
74
|
+
end
|
75
|
+
end
|
76
|
+
run_tests
|
77
|
+
|
78
|
+
if @tests_failed.size == 0
|
79
|
+
TEST_OUT.puts "All Tests Completed Successfully"
|
80
|
+
eputs "All Tests Completed Successfully" unless TEST_OUT == STDERR
|
81
|
+
else
|
82
|
+
eputs "Tests Were Failed"
|
83
|
+
@tests_failed.each do |name, hash|
|
84
|
+
sep = "----------------------------------------------"
|
85
|
+
TEST_OUT.puts '', sep, " Test Failed", sep
|
86
|
+
TEST_OUT.puts "Name: #{name}"
|
87
|
+
TEST_OUT.puts "Description: \n#{hash[:description]}", ''
|
88
|
+
TEST_OUT.puts "This test failed on these checks: #{hash[:checks_failed]}", ''
|
89
|
+
TEST_OUT.puts sep, ''
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
# Check to see which run has completed and run tests for those runs.
|
96
|
+
|
97
|
+
def self.run_tests
|
98
|
+
eputs "Waiting for runs to complete"
|
99
|
+
loop do
|
100
|
+
break if @submitted_tests.size ==0
|
101
|
+
@test_runner.update(false)
|
102
|
+
i = 0
|
103
|
+
loop do
|
104
|
+
tst = @submitted_tests[0]
|
105
|
+
run = @test_runner.runs.find{|run| run.run_name == tst}
|
106
|
+
if [:Complete, :Failed].include? run.status
|
107
|
+
run_checks run
|
108
|
+
@submitted_tests.delete(tst)
|
109
|
+
end
|
110
|
+
i += 1
|
111
|
+
break if i >= @submitted_tests.size
|
112
|
+
end
|
113
|
+
sleep 3
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
# Run the test case with the given input file.
|
119
|
+
|
120
|
+
def self.submit_run(test_case)
|
121
|
+
|
122
|
+
dir = results_folder(test_case)
|
123
|
+
input_text = File.read("#{test_case_folder(test_case)}/#{test_case}.in")
|
124
|
+
|
125
|
+
description = input_text.scan(Regexp.new("#{/^\s*!\s*description\s*=\s* /}(#{Regexp.quoted_string})")).flatten[0]
|
126
|
+
(eputs "----Rejecting '#{file}', no description provided or description is not in the correct format: description = \" description \"";return) unless description
|
127
|
+
run = Astrogk.new(@test_runner)
|
128
|
+
|
129
|
+
# This cryptic statement updates the run parameters from the input file
|
130
|
+
run.instance_eval(
|
131
|
+
Astrogk.defaults_file_text_from_input_file("#{test_case_folder(test_case)}/#{test_case}.in"))
|
132
|
+
|
133
|
+
run.run_name = test_case
|
134
|
+
run.instance_variable_set(:@dir_name, dir)
|
135
|
+
@test_runner.test_submission = true
|
136
|
+
@test_runner.submit(run)
|
137
|
+
|
138
|
+
other_files = Dir.entries(test_case_folder(test_case)).find_all do |f|
|
139
|
+
not (f =~ /\.in/ or f =~ /\.out\.nc/ or f =~ /\.svn/ or [".", ".."].include? f)
|
140
|
+
end
|
141
|
+
other_files.each do |f|
|
142
|
+
# p f
|
143
|
+
FileUtils.cp(test_case_folder(test_case)+'/'+f, results_folder(test_case)+'/'+f)
|
144
|
+
end
|
145
|
+
|
146
|
+
@test_runner.test_submission = false
|
147
|
+
@test_runner.submit(run)
|
148
|
+
@submitted_tests.push run.run_name
|
149
|
+
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
def self.run_checks(run)
|
154
|
+
checks_failed = []
|
155
|
+
|
156
|
+
input_text = File.read("#{test_case_folder(run.run_name)}/#{run.run_name}.in")
|
157
|
+
description = input_text.scan(Regexp.new("#{/^\s*!\s*description\s*=\s* /}(#{Regexp.quoted_string})")).flatten[0]
|
158
|
+
description.gsub!(/(.{25,45} |.{45})/){"#$1\n"} if description
|
159
|
+
if input_text =~ Regexp.new("#{/^\s*!\s*custom_checks\s*=\s* /}(#{Regexp.properly_nested("\\[", "\\]", false)})")
|
160
|
+
custom_checks = eval($1)
|
161
|
+
custom_checks.each{|check| checks_failed.push check unless run.run_check check}
|
162
|
+
else
|
163
|
+
checks_failed.push :standard unless run.run_check :standard
|
164
|
+
end
|
165
|
+
unless checks_failed.size == 0
|
166
|
+
@tests_failed[run.run_name] = {checks_failed: checks_failed, description: description}
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Relative error which differences cannot exceed in the standard case
|
171
|
+
|
172
|
+
TOLERANCE = 1.0e-10
|
173
|
+
|
174
|
+
# A list of variables that are allowed to be different in the standard test
|
175
|
+
|
176
|
+
EXCLUDED_VARIABLES = ['input_file']
|
177
|
+
|
178
|
+
# Check the results against standard cases using the checks described here. Any custom tests should be implemented here!
|
179
|
+
|
180
|
+
def run_check(check)
|
181
|
+
netcdf_standard_case = NumRu::NetCDF.open(TestAstrogk.test_case_folder(@run_name) + '/' + @run_name + '.out.nc')
|
182
|
+
Dir.chdir(@directory) do
|
183
|
+
case check
|
184
|
+
when :standard
|
185
|
+
netcdf = NumRu::NetCDF.open(@run_name + '.out.nc')
|
186
|
+
netcdf.vars.map{|v| v.name}.each do |v|
|
187
|
+
unless netcdf_standard_case.var(v)
|
188
|
+
TEST_OUT.puts "Warning: variable '#{v}' is missing from the test case netcdf output for '#@run_name'. Suggest updating the test case netcdf file. This is not a GS2 fault."
|
189
|
+
end
|
190
|
+
end
|
191
|
+
netcdf_standard_case.vars.map{|v| v.name}.each do |v|
|
192
|
+
next if EXCLUDED_VARIABLES.include? v
|
193
|
+
begin
|
194
|
+
unless netcdf.var(v)
|
195
|
+
TEST_OUT.puts "Error: Variable #{v} is missing from the netcdf output for #@run_name"
|
196
|
+
return false
|
197
|
+
end
|
198
|
+
|
199
|
+
narray = netcdf.var(v).get
|
200
|
+
standard_narray = netcdf_standard_case.var(v).get
|
201
|
+
|
202
|
+
if standard_narray.abs.max < TOLERANCE
|
203
|
+
if narray.abs.max < TOLERANCE
|
204
|
+
next
|
205
|
+
else
|
206
|
+
TEST_OUT.puts "Error: Variable '#{v}' has failed check in '#@run_name'"
|
207
|
+
return false
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
|
212
|
+
difference = narray - standard_narray
|
213
|
+
return false unless difference.abs.max / standard_narray.abs.max < TOLERANCE
|
214
|
+
# ep 'var', difference.abs.max
|
215
|
+
rescue => err
|
216
|
+
TEST_OUT.puts "Error: #{err}"
|
217
|
+
TEST_OUT.puts "Error: Variable '#{v}' has failed check in '#@run_name'"
|
218
|
+
return false
|
219
|
+
end
|
220
|
+
end
|
221
|
+
return true
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
|
227
|
+
end #module TestAstrogk
|
228
|
+
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
@@ -0,0 +1,200 @@
|
|
1
|
+
##########################################
|
2
|
+
# = Code Runner GS2 Module
|
3
|
+
##########################################
|
4
|
+
#
|
5
|
+
# Authors: Edmund Highcock
|
6
|
+
# Copyright: 2009 Edmund Highcock
|
7
|
+
#
|
8
|
+
# This is free software released under the GPL v3
|
9
|
+
#
|
10
|
+
# This module allows easy running of the plasma turbulence simulation code gs2 using Code Runner, by automatically organising, naming and submitting runs, and analysing the run data.
|
11
|
+
#
|
12
|
+
# See Code Runner documentation, or documentation for individual methods.
|
13
|
+
#
|
14
|
+
# Notes
|
15
|
+
#
|
16
|
+
# index variables, e.g. kx_index, ky_index etc always refer to the 1-based Fortran index, to keep correspondance with the gs2 indices. Element variables, e.g. kx_element, always refer to the 0-based C/ruby index
|
17
|
+
#
|
18
|
+
# raw NumRu::NetCDF grids are in Fortran row-major order. This means that when you access grids using the NetCDF function NetCDF#get, you must specify the indices in fortran order (but 0-based!). The NetCDF#get function then returns a C-like NArray with the indices in the opposite order. You can convert this to a Ruby Array using the method NArray#to_a (the indices will still be in the same order).
|
19
|
+
|
20
|
+
|
21
|
+
#
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
class CodeRunner
|
26
|
+
|
27
|
+
|
28
|
+
#CodeRunner.setup_run_class('g2') # Astrogk Inherits from GS2
|
29
|
+
|
30
|
+
# This is a customised subclass of CodeRunner::Run which allows CodeRunner to submit and analyse simulations from the gyrokinetic flux tube code AstroGK, which is principally used for simulating plasmas in magnetic confinement fusion.
|
31
|
+
#
|
32
|
+
# It performs two distinct roles: submitting simulations and analysing the data.
|
33
|
+
#
|
34
|
+
# = Submitting Simulations
|
35
|
+
#
|
36
|
+
# This principally involves generating the input file, which is a very nontrivial task. In order to do this, it maintains a complete record of every possible input parameter for AstroGK, as well as what datatype that parameter is, and sometimes what values it is allowed to take. This allows that not only to generate the input file, but to check that the input file makes sense. However, although generating the input file works beautifully, the set of sanity checks that it makes is not exhaustive: intelligent use is still required!
|
37
|
+
#
|
38
|
+
# In tandem with this, it maintains a whole set of tools for manipulating its database of input parameters. This includes updating their allowed values and also editing and accessing help for every input parameter.
|
39
|
+
#
|
40
|
+
# = Analysing Simulations
|
41
|
+
#
|
42
|
+
# The amount of analysis possible on AstroGK data is enormous, and CodeRunner hasn't got close to getting there. What it can do is:
|
43
|
+
#
|
44
|
+
# * Check if the run is complete by comparing the number of completed timesteps against nstep
|
45
|
+
# * Calculate growth rates for linear runs.
|
46
|
+
# * Check if non-linear runs have saturated and calculate fluxes for those runs.
|
47
|
+
# * Automatically plot a huge variety of different graphs, ranging from simple plots of heat flux versus time to three-dimensional plots of the spectrum and potential.
|
48
|
+
|
49
|
+
|
50
|
+
class Gs2::Astrogk < Gs2
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
def agk?
|
55
|
+
true
|
56
|
+
end
|
57
|
+
|
58
|
+
# Include the other files
|
59
|
+
@code_module_folder = folder = File.dirname(File.expand_path(__FILE__)) + '/astrogk' # i.e. the directory this file is in
|
60
|
+
setup_namelists(folder)
|
61
|
+
require folder + '/graphs.rb'
|
62
|
+
# require folder + '/namelist_tools.rb'
|
63
|
+
# require folder + '/input_file_tools.rb'
|
64
|
+
require folder + '/gsl_data.rb'
|
65
|
+
require folder + '/check_convergence.rb'
|
66
|
+
require folder + '/calculations.rb'
|
67
|
+
require folder + '/ingen.rb'
|
68
|
+
require folder + '/properties.rb'
|
69
|
+
require folder + '/test_gs2.rb'
|
70
|
+
|
71
|
+
NaN = GSL::NAN
|
72
|
+
# GSL::Neg
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
################################################
|
79
|
+
# Quantities that are calculated or determined by CodeRunner
|
80
|
+
# after the simulation has ended, i.e. quantities
|
81
|
+
# that are not available from the AstroGK output files.
|
82
|
+
################################################
|
83
|
+
# Get GS2 results and add any
|
84
|
+
# astrogk ones (currently empty)
|
85
|
+
|
86
|
+
@results = rcp.results + []
|
87
|
+
|
88
|
+
###############################################
|
89
|
+
# Other useful information about the run
|
90
|
+
###############################################
|
91
|
+
|
92
|
+
@astrogk_run_info = rcp.gs2_run_info + []
|
93
|
+
|
94
|
+
@run_info = @astrogk_run_info.dup
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
@naming_pars = rcp.naming_pars + []
|
99
|
+
|
100
|
+
@code_long = "AstroGK Astrophysical Gyrokinetic Code"
|
101
|
+
|
102
|
+
@excluded_sub_folders =[]
|
103
|
+
|
104
|
+
def run_namelist_backwards_compatibility
|
105
|
+
end
|
106
|
+
def set_nprocs
|
107
|
+
|
108
|
+
if (nprocs_in = @nprocs) =~ /^x/
|
109
|
+
max = max_nprocs_no_x
|
110
|
+
#Astrogk seems to not like you actually having naky * nspec * negrid processors.. reduce it
|
111
|
+
for i in 2...max
|
112
|
+
if max%i ==0
|
113
|
+
max = max / i
|
114
|
+
break
|
115
|
+
end
|
116
|
+
end
|
117
|
+
nodes = 0
|
118
|
+
@nprocs = "#{nodes}#{nprocs_in}"
|
119
|
+
loop do
|
120
|
+
nodes += 1
|
121
|
+
@nprocs = "#{nodes}#{nprocs_in}"
|
122
|
+
if actual_number_of_processors > max
|
123
|
+
nodes -= 1
|
124
|
+
@nprocs = "#{nodes}#{nprocs_in}"
|
125
|
+
break
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
def input_file_header
|
131
|
+
<<EOF
|
132
|
+
!==============================================================================
|
133
|
+
! AstroGK INPUT FILE automatically generated by CodeRunner
|
134
|
+
!==============================================================================
|
135
|
+
!
|
136
|
+
! AstroGK is a gyrokinetic flux tube initial value turbulence code
|
137
|
+
! which can be used for fusion or astrophysical plasmas.
|
138
|
+
!
|
139
|
+
! See http://gyrokinetics.sourceforge.net
|
140
|
+
!
|
141
|
+
! CodeRunner is a framework for the automated running and analysis
|
142
|
+
! of large simulations.
|
143
|
+
!
|
144
|
+
! See http://coderunner.sourceforge.net
|
145
|
+
! by CodeRunner version #{CodeRunner::CODE_RUNNER_VERSION.to_s}
|
146
|
+
!
|
147
|
+
!==============================================================================
|
148
|
+
|
149
|
+
EOF
|
150
|
+
end
|
151
|
+
def self.defaults_file_header
|
152
|
+
<<EOF1
|
153
|
+
######################################################################
|
154
|
+
# Automatically generated defaults file for AstroGK CodeRunner module#
|
155
|
+
# #
|
156
|
+
# This defaults file specifies a set of defaults for AstroGK which are#
|
157
|
+
# used by CodeRunner to set up and run GS2 simulations. #
|
158
|
+
# #
|
159
|
+
# Created #{Time.now.to_s} #
|
160
|
+
# #
|
161
|
+
######################################################################
|
162
|
+
|
163
|
+
@defaults_file_description = ""
|
164
|
+
EOF1
|
165
|
+
end
|
166
|
+
|
167
|
+
@source_code_subfolders = ['utils']
|
168
|
+
|
169
|
+
folder = File.dirname(File.expand_path(__FILE__)) # i.e. the directory this file is in
|
170
|
+
|
171
|
+
def self.transfer_gs2_docs
|
172
|
+
CodeRunner.setup_run_class('gs2')
|
173
|
+
p CodeRunner::Astrogk.ancestors
|
174
|
+
intersection = (CodeRunner::Gs2.rcp.namelists.keys&CodeRunner::Astrogk.rcp.namelists.keys)
|
175
|
+
gs2namelists=CodeRunner::Gs2.rcp.namelists
|
176
|
+
intersection.each do | namelist |
|
177
|
+
p namelist
|
178
|
+
gs2namelist=gs2namelists[namelist]
|
179
|
+
next unless gs2namelist
|
180
|
+
self.rcp.namelists[namelist][:variables].each do | varname, varhash |
|
181
|
+
p varname
|
182
|
+
if match = (gs2namelist[:variables][varname]) # or gs2namelist[:variables].find{|gs2varname,gs2varhash| gs2varhash[:code_name]==varhash[:code_name]}[1])
|
183
|
+
puts "Found corresponding variable #{varname}"
|
184
|
+
#p match
|
185
|
+
puts "Found help: #{match[:help]}"
|
186
|
+
varhash[:help] = match[:help] if match[:help]
|
187
|
+
varhash[:description] = match[:description]
|
188
|
+
save_namelists
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end # class Astrogk
|
195
|
+
# For backwards compatibility
|
196
|
+
Astrogk = Gs2::Astrogk
|
197
|
+
|
198
|
+
end # class CodeRunner
|
199
|
+
|
200
|
+
|