rb-daspk 0.0.7-x86-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,130 @@
1
+ # Copyright (c) 2009 Eric Todd Meyers
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person
4
+ # obtaining a copy of this software and associated documentation
5
+ # files (the "Software"), to deal in the Software without
6
+ # restriction, including without limitation the rights to use,
7
+ # copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the
9
+ # Software is furnished to do so, subject to the following
10
+ # conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ # OTHER DEALINGS IN THE SOFTWARE.
23
+ #
24
+ #
25
+ # More information, source code and gems @ http://rubyforge.org/projects/rb-daspk/
26
+ #
27
+
28
+ require 'rubygems'
29
+ require 'rb-daspk'
30
+ include DASPK
31
+
32
+ #
33
+ # classic spring mass problem
34
+ #
35
+ # d2x/dt + 2*l*w0*dxdt + w0*w0*x = 0
36
+ #
37
+ # let v = dx/dt, then
38
+ #
39
+ # 1. dxdt - v = 0
40
+ # 2. dvdt + 2*l*w0*v + w0*w0*x = 0
41
+ #
42
+ #
43
+ # let's start with x at 1, dxdt at 0 (v=0)
44
+ # we'll ask DASPK for the state derivatives
45
+ #
46
+ y = [1.0,0.0]
47
+ yprime= [0.0,0.0] # these are gusses in this case. we will call solveForInitialValues to get them
48
+
49
+
50
+ w0 = 1.0
51
+ l = 0.0 # undamped
52
+
53
+ #
54
+ # in case we want to see details during the integration. in this case were just dumping values
55
+ # not required (can pass nil to Solver.new if you want)
56
+ #
57
+ inter = Proc.new do |time,y,yprime|
58
+ print " time = #{time} x = #{y[0]}\n"
59
+ end
60
+
61
+ jac = Proc.new do |time,y,yprime,jacm,cj|
62
+
63
+ jacm[0][0] = cj
64
+ jacm[0][1] = -1.0
65
+ jacm[1][0] = w0**2.0
66
+ jacm[1][1] = (2*l*w0 + cj)
67
+
68
+ end
69
+
70
+ s=Solver.new(2,y,yprime,inter,jac) do |time,y,yprime,delta|
71
+ #s=Solver.new(2,y,yprime) do |time,y,yprime,delta|
72
+ delta[0] = yprime[0] - y[1]
73
+ delta[1] = yprime[1] + 2.0*l*w0*y[1] + w0*w0*y[0]
74
+ end
75
+
76
+
77
+ #
78
+ # solve the initial value problem
79
+ # note, this isnt required if the y and yprimes are already consistent
80
+ #
81
+ # return code from solveFoeInitialValues
82
+ # 4 success (see DDASPK for all possible values)
83
+ #
84
+ idid = s.solve_for_initial_values(0,y,yprime,[0,0])
85
+ print " ----------------------------------------\n"
86
+ print " initial conditions\n"
87
+ print " x = #{y[0]}\n"
88
+ print " vel = #{y[1]}\n"
89
+ print " accelaration = #{yprime[1]}\n"
90
+ print " ----------------------------------------\n"
91
+
92
+ #
93
+ # integrate to PI seconds
94
+ #
95
+ #
96
+ ans = s.solve(0.0,Math::PI)
97
+ #
98
+ # answer is an array of arrays
99
+ # ans[0] = end time
100
+ # ans[1] = end y array
101
+ # ans[2] = end yprime array
102
+ # ans[3] = DASPK return code (see DDASPK.F for meaning)
103
+ #
104
+ print " ----------------------------------------\n"
105
+ print " final conditions\n"
106
+ print " time = #{ans[0]}\n"
107
+ print " x = #{ans[1][0]}\n"
108
+ print " vel = #{ans[1][1]}\n"
109
+ print " accelaration = #{ans[2][1]}\n"
110
+ print " ----------------------------------------\n"
111
+
112
+ #
113
+ # continue to integrate to 2PI seconds
114
+ #
115
+ #
116
+ ans = s.solve(0.0,2*Math::PI)
117
+ #
118
+ # answer is an array of arrays
119
+ # ans[0] = end time
120
+ # ans[1] = end y array
121
+ # ans[2] = end yprime array
122
+ # ans[3] = DASPK return code (see DDASPK.F for meaning)
123
+ #
124
+ print " ----------------------------------------\n"
125
+ print " final conditions\n"
126
+ print " time = #{ans[0]}\n"
127
+ print " x = #{ans[1][0]}\n"
128
+ print " vel = #{ans[1][1]}\n"
129
+ print " accelaration = #{ans[2][1]}\n"
130
+ print " ----------------------------------------\n"
Binary file
@@ -0,0 +1,328 @@
1
+ # Copyright (c) 2009 Eric Todd Meyers
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person
4
+ # obtaining a copy of this software and associated documentation
5
+ # files (the "Software"), to deal in the Software without
6
+ # restriction, including without limitation the rights to use,
7
+ # copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the
9
+ # Software is furnished to do so, subject to the following
10
+ # conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ # OTHER DEALINGS IN THE SOFTWARE.
23
+ #
24
+ #
25
+ # More information, source code and gems @ http://rubyforge.org/projects/rb-daspk/
26
+ #
27
+ #:main:DASPK::Solver
28
+ #
29
+
30
+
31
+ require 'rubygems'
32
+ require 'ffi'
33
+
34
+ WINDOZE = Config::CONFIG['host_os'] =~ /mswin|mingw/
35
+ LINUX=RUBY_PLATFORM.downcase.include?("linux")
36
+ OSX=RUBY_PLATFORM.downcase.include?("darwin")
37
+
38
+ module FFI
39
+ class Pointer
40
+ def read_double
41
+ get_float64(0)
42
+ end
43
+
44
+ def write_double(obj)
45
+ put_float64(0, obj)
46
+ end
47
+
48
+ def read_array_of_double(length)
49
+ get_array_of_double(0, length)
50
+ end
51
+
52
+ def write_array_of_double(ary)
53
+ put_array_of_double(0, ary)
54
+ end
55
+ end
56
+ end
57
+
58
+
59
+ module DASPKLIB
60
+ extend FFI::Library
61
+ if (OSX) then
62
+ ffi_lib File.dirname(__FILE__) + '/libdaspk.dylib'
63
+ elsif (WINDOZE)
64
+ ffi_lib File.dirname(__FILE__) + '/daspk.dll'
65
+ elsif (LINUX)
66
+ ffi_lib File.dirname(__FILE__) + '/libdaspk.so'
67
+ end
68
+
69
+ callback :jac, [:pointer,:pointer,:pointer,:pointer,:pointer,:pointer,:pointer], :void
70
+ callback :res, [:pointer,:pointer,:pointer,:pointer,:pointer,:pointer,:pointer,:pointer], :void
71
+ attach_function 'ddaspk_', [:res, :pointer,:pointer,:pointer,:pointer,:pointer,:pointer,:pointer,:pointer,:pointer,
72
+ :pointer,:pointer,:pointer,:pointer,:pointer,:pointer,:jac, :pointer], :void
73
+ attach_function 'd1mach_', [:pointer],:double
74
+ end
75
+
76
+ module DASPK
77
+ #
78
+ # interface to DASPK
79
+ #
80
+ # typical usage
81
+ #
82
+ # 1. create an instance of the Solver class. pass in the initial states/derivatives and the residual function as a block
83
+ # 2. if the initial conditions are not consistent call solveForInitialValues
84
+ # 3. call solve with the start and end times desired
85
+ # 4. repeated calls to solve will solve to each end time. the start time is ingored. this allows
86
+ # for continued integration
87
+ #
88
+ class Solver
89
+
90
+ include DASPKLIB
91
+ attr_accessor :rtol,:atol,:inter,:jac,:maxstep
92
+ #
93
+ #
94
+ # * neq = the number of equations. this is always the sum of the number of states and algebraics
95
+ # * y = array containing the initial states and algebraics
96
+ # * yprime = array containing the initial state derivatives
97
+ # * inter = Proc instance. defaults to nil. if non-nil used as a callback to report the integration results at every time step
98
+ # * jac = Proc instance. defauls to nil. if non-nil used to get the modified Jacbian matrix. otherwise DASPK will determine by iteration
99
+ # * res = residual (delta) Proc. must be present. this is responsible for filling of the delta (residual) array.
100
+ #
101
+ def initialize (neq, y, yprime, inter=nil, jac=nil, &res)
102
+ @lwr = 15000
103
+ @lwi = 15000
104
+ @plwr = FFI::MemoryPointer.new(:int)
105
+ @plwr.write_int(@lwr)
106
+ @plwi = FFI::MemoryPointer.new(:int)
107
+ @plwi.write_int(@lwi)
108
+ @iwork = [0]*@lwi
109
+ @work = [0]*@lwr
110
+ @pwork = FFI::MemoryPointer.new(:double,@lwr)
111
+ @piwork = FFI::MemoryPointer.new(:int,@lwi)
112
+ @info = [0]*30
113
+ @pinfo = FFI::MemoryPointer.new(:int,30)
114
+ @ialgs = [0]*neq
115
+ @res = res
116
+ @inter = inter
117
+ @rtol = 0.000001
118
+ @atol = 0.000001
119
+ @jac = jac
120
+ @maxstep = 0
121
+
122
+
123
+ if (inter) then
124
+ @info[2]=1
125
+ end
126
+
127
+ @neq = neq
128
+ @pneq = FFI::MemoryPointer.new(:int)
129
+ @pneq.write_int(neq)
130
+ @y = y
131
+ @yprime = yprime
132
+
133
+ @py = FFI::MemoryPointer.new(:double,neq)
134
+ @py.write_array_of_double(y)
135
+ @pyprime = FFI::MemoryPointer.new(:double,neq)
136
+ @pyprime.write_array_of_double(yprime)
137
+
138
+ @prtol = FFI::MemoryPointer.new(:double)
139
+ @patol = FFI::MemoryPointer.new(:double)
140
+
141
+ #
142
+ # residual proc called from the Fortran. Let's pass it onto the user's residual procedure
143
+ # in a easier to use form
144
+ #
145
+ @resproc = Proc.new do |p1,p2,p3,p4,p5,p6,p7,p8|
146
+ delta = p5.read_array_of_double(@neq)
147
+ @res.call(p1.read_double,p2.read_array_of_double(@neq),p3.read_array_of_double(@neq),delta)
148
+ p5.write_array_of_double(delta)
149
+ end
150
+
151
+ #
152
+ # jacobian proc called from the Fortran. Let's pass it onto the user's jacboian procedure
153
+ # in a easier to use form
154
+ #
155
+ @jacproc = Proc.new do |p1,p2,p3,p4,p5,p6,p7|
156
+ all = p4.read_array_of_double(@neq*@neq)
157
+ jacm = Array.new
158
+ for i in 0..(@neq-1) do
159
+ arow = Array.new
160
+ for j in 0..(@neq-1) do
161
+ arow << all[j*@neq+i] # Fortran stores in column major, though references in row major
162
+ end
163
+ jacm << arow
164
+ end
165
+
166
+ @jac.call(p1.read_double,p2.read_array_of_double(@neq),p3.read_array_of_double(@neq),jacm,p5.read_double)
167
+
168
+ p4.write_array_of_double(jacm.transpose.flatten) # Fortran stores in column major, though references in row major
169
+ end
170
+
171
+
172
+
173
+
174
+ end
175
+ #
176
+ # solve the initial value problem
177
+ # this is only required if the Y's and Y'primes are not
178
+ # already consistent
179
+ #
180
+ # the contents of y or yprime will be modified
181
+ #
182
+ # init=
183
+ # * 1 compute derivatives and algebraics from states
184
+ # * 2 compute algebraics and states from derivatives
185
+ #
186
+ # ialgs = an array indicating which Y's are algebraics
187
+ # 0 means it is a state (aka has derivative in the equations)
188
+ # 1 means it is an algebraic
189
+ #
190
+ def solve_for_initial_values(time,y,yprime,ialgs,init=1,mxnit=5,mxnj=6,mxnh=5,lsoff=0,stptol=0,epinit=0.01)
191
+
192
+ @mxnit = mxnit
193
+ @mxnj = mxnj
194
+ @mxnh = mxnh
195
+ @lsoff = lsoff
196
+ pidum = FFI::MemoryPointer.new(:int)
197
+ @stptol = (stptol==0 ? d1mach_(pidum)**(2.0/3.0) : stptol)
198
+ @epinit = epinit
199
+ @info[16] = 1
200
+ @iwork[31] = @mxnit
201
+ @iwork[32] = @mxnj
202
+ @iwork[33] = @mxnh
203
+ @iwork[34] = @lsoff
204
+ @work[13] = @stptol
205
+ @work[14] = @epinit
206
+
207
+ ptime = FFI::MemoryPointer.new(:double)
208
+ ptout = FFI::MemoryPointer.new(:double)
209
+ pidid = FFI::MemoryPointer.new(:int)
210
+ @y = y
211
+ @yprime = yprime
212
+
213
+ ptime.write_double(time)
214
+ ptout.write_double(time+1)
215
+ @py.write_array_of_double(@y)
216
+ @pyprime.write_array_of_double(@yprime)
217
+ @prtol.write_double(@rtol)
218
+ @patol.write_double(@atol)
219
+
220
+ if (init==1) then
221
+ @info[10]=1
222
+ for i in 0..(@neq-1) do
223
+ @iwork[40+i] = (ialgs[i]==1 ? -1 : 1)
224
+ end
225
+ @info[13]=1
226
+ @piwork.write_array_of_int(@iwork)
227
+ @pwork.write_array_of_double(@work)
228
+ @pinfo.write_array_of_int(@info)
229
+ ddaspk_(@resproc,@pneq,ptime,@py,@pyprime,ptout,@pinfo,@prtol,@patol,pidid,@pwork,@plwr,@piwork,@plwi,nil,nil,@jacproc,nil)
230
+ @y.replace @py.read_array_of_double(@neq)
231
+ @yprime.replace @pyprime.read_array_of_double(@neq)
232
+ idid = pidid.read_int
233
+ elsif (init==2) then
234
+ @info[10]=2
235
+ for i in 0..(@neq-1) do
236
+ @iwork[40+i] = (ialgs[i]==1 ? -1 : 1)
237
+ end
238
+ @info[13]=1
239
+ @piwork.write_array_of_int(@iwork)
240
+ @pwork.write_array_of_double(@work)
241
+ @pinfo.write_array_of_int(@info)
242
+ ddaspk_(@resproc,@pneq,ptime,@py,@pyprime,ptout,@pinfo,@prtol,@patol,pidid,@pwork,@plwr,@piwork,@plwi,nil,nil,@jacproc,nil)
243
+ @y.replace @py.read_array_of_double(@neq)
244
+ @yprime.replace @pyprime.read_array_of_double(@neq)
245
+ idid = pidid.read_int
246
+ end
247
+ @info[13] = 0
248
+ @info[10] = 0
249
+ @info[0] = 0
250
+ @info[16] = 0
251
+ idid
252
+
253
+ end
254
+
255
+ def solve (time, tout)
256
+ #
257
+ # solver options
258
+ #
259
+
260
+ @prtol.write_double(@rtol)
261
+ @patol.write_double(@atol)
262
+
263
+ #
264
+ # user supply an explicit Jacobian?
265
+ #
266
+ if (@jac) then
267
+ @info[4]=1
268
+ else
269
+ @info[4]=0
270
+ end
271
+ #
272
+ # maximum time step option
273
+ #
274
+ if (@maxstep!=0) then
275
+ @info[6]=1
276
+ @work[1]=@maxstep
277
+ else
278
+ @info[6]=0
279
+ @work[1]=@maxstep
280
+ end
281
+
282
+ #
283
+ # starting time
284
+ #
285
+ ptime = FFI::MemoryPointer.new(:double)
286
+ ptime.write_double(time)
287
+
288
+ #
289
+ # ending time
290
+ #
291
+ ptout = FFI::MemoryPointer.new(:double)
292
+ ptout.write_double(tout)
293
+
294
+ idid=1
295
+ pidid = FFI::MemoryPointer.new(:int)
296
+ pidid.write_int(idid)
297
+ @pwork.write_array_of_double(@work)
298
+ @piwork.write_array_of_int(@iwork)
299
+ @pinfo.write_array_of_int(@info)
300
+
301
+ while (idid==1) do
302
+ ddaspk_(@resproc,@pneq,ptime,@py,@pyprime,ptout,@pinfo,@prtol,@patol,pidid,@pwork,@plwr,@piwork,@plwi,nil,nil,@jacproc,nil)
303
+ idid = pidid.read_int
304
+ #
305
+ # report intermediate values ?
306
+ #
307
+ if ((idid==1)&&(@inter)) then
308
+ @inter.call(ptime.read_double,@py.read_array_of_double(@neq),@pyprime.read_array_of_double(@neq))
309
+ end
310
+
311
+ end
312
+
313
+ @work = @pwork.read_array_of_double(@lwr) # save the working ram
314
+ @iwork = @piwork.read_array_of_int(@lwi)
315
+ @info[0] = 1
316
+ [ptime.read_double,@py.read_array_of_double(@neq),@pyprime.read_array_of_double(@neq),idid]
317
+
318
+ end
319
+
320
+ def reset
321
+ @info[0]=0
322
+ @py.write_array_of_double(@y)
323
+ @pyprime.write_array_of_double(@yprime)
324
+ end
325
+
326
+ end
327
+
328
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rb-daspk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.7
5
+ platform: x86-linux
6
+ authors:
7
+ - Eric Meyers
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-19 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: ffi
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.5.3
24
+ version:
25
+ description: Allows users to solve differential algebraic equations in Ruby, using Ruby constructs. Interfaces with the DASPK Fortran library. DASPK solves DAE's of the form G(t,y,y',p) = 0
26
+ email: etm@ericmeyers.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - lib/rb-daspk.rb
35
+ - examples/springmass.rb
36
+ - lib/libdaspk.so
37
+ has_rdoc: true
38
+ homepage: http://rb-daspk.rubyforge.org
39
+ licenses: []
40
+
41
+ post_install_message:
42
+ rdoc_options:
43
+ - -S
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: "0"
51
+ version:
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ requirements: []
59
+
60
+ rubyforge_project: rb-daspk
61
+ rubygems_version: 1.3.5
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: DASPK Ruby Interface. Allows users to solve differential algebraic equations in Ruby, using Ruby constructs. Interfaces with the DASPK Fortran library. DASPK solves DAE's of the form G(t,y,y',p) = 0
65
+ test_files: []
66
+