8 REAL(rprec),
PARAMETER :: zero = 0
13 TYPE (bsc_coil),
POINTER :: single_coil => null()
14 TYPE (bsc_coilcoll),
DIMENSION(:),
ALLOCATABLE,
TARGET ::
27 SUBROUTINE initialize_biotsavart (extcur_in, extension,
33 REAL(rprec),
INTENT(in),
DIMENSION(:) :: extcur_in
34 REAL(rprec),
DIMENSION(:,:),
OPTIONAL :: xpt
35 LOGICAL,
OPTIONAL :: scaled
36 CHARACTER(LEN=*),
OPTIONAL :: extension
40 TYPE(bsc_coil) :: coil_temp
42 INTEGER :: nextcur, ig, nc
43 REAL(rprec) :: current, current_first
44 CHARACTER(len=200) :: coil_file
45 LOGICAL :: scaled_or_raw
47 scaled_or_raw = .true.
48 IF (
PRESENT(scaled)) scaled_or_raw = scaled
50 IF (
PRESENT(extension))
THEN
52 coil_file =
'coils.' // trim(extension)
53 CALL parse_coils_file (trim(coil_file))
56 nextcur =
SIZE(coil_group)
57 IF (scaled_or_raw)
THEN
59 DO nc = 1, coil_group(ig) % ncoil
60 current = coil_group(ig) % coils(nc) % current
61 IF (nc .eq. 1) current_first = current
62 IF (current_first .ne. zero)
63 1 coil_group(ig) % coils(nc) % current =
64 1 (current/current_first)*extcur_in(ig)
69 ELSE IF (
PRESENT(xpt))
THEN
72 CALL cleanup_biotsavart
75 ALLOCATE (single_coil)
77 & extcur_in(1),xpt(1:3,1:nc))
80 stop
'Fatal: initialize_bs: xpt or extension must be specified'
83 END SUBROUTINE initialize_biotsavart
89 SUBROUTINE parse_coils_file (coil_file, lgrps)
95 CHARACTER(LEN=*) :: coil_file
96 LOGICAL,
OPTIONAL :: lgrps
100 INTEGER,
PARAMETER :: iou_coil0=22
101 INTEGER,
PARAMETER :: maxgroups = 1000
105 INTEGER :: istat, i_line
106 INTEGER,
DIMENSION(:) :: ngroup(maxgroups)
107 INTEGER :: nmaxnodes, iou_coil, nextcur
108 INTEGER :: n_line_start_string, n_line_skip
109 CHARACTER(LEN=200) :: line, group, line_lc
110 CHARACTER(LEN=28) :: start_string =
'** coils_dot_starts_below **'
111 LOGICAL :: local_lgrps
117 CALL safe_open(iou_coil, istat, trim(coil_file),
'old',
119 IF (istat .ne. 0) stop
'Error opening input coil file'
126 n_line_start_string = 0
129 READ(iou_coil,
'(a)',
END = 100, IOSTAT=istat) line
130 IF (istat .ne. 0)
THEN
131 WRITE(6,*)
'Problem in parse_coils_file. istat =',istat
132 WRITE(6,*)
' Line number is ', i_line
137 CALL tolower(line_lc)
138 istat = index(line, start_string)
139 IF (istat .eq. 0)
THEN
142 n_line_start_string = i_line
143 WRITE(6,*)
'Found start_string: ', start_string
144 WRITE(6,*)
' in line ', n_line_start_string
149 100
IF (n_line_start_string .eq. 0)
THEN
150 rewind(iou_coil, iostat=istat)
151 IF (istat .ne. 0)
THEN
152 WRITE(6,*)
'Problem 2 in parse_coils_file. istat =',istat
157 n_line_skip = 3 + n_line_start_string
160 READ (iou_coil,
'(a)' , iostat=istat) line
161 istat = index(line,
'periods')
163 & stop
'First line of coils file must contain # periods'
164 READ (line, *, iostat=istat) group, nfp_bs
166 local_lgrps = .false.
167 IF (
PRESENT(lgrps)) local_lgrps = lgrps
171 CALL read_coils_pass1(iou_coil, nextcur, nmaxnodes, ngroup,
172 & local_lgrps, n_line_skip)
176 IF (nextcur .gt. 0)
THEN
177 CALL cleanup_biotsavart
178 ALLOCATE (coil_group(nextcur), stat=istat)
179 IF (istat .ne. 0) stop
'ERROR ALLOCATION COIL COLLECTION'
181 WRITE(*,*)
'number coilgroups = ',nextcur,
' <= 0 '
187 CALL read_coils_pass2(iou_coil, nmaxnodes, coil_group, ngroup,
188 & local_lgrps, n_line_skip)
190 END SUBROUTINE parse_coils_file
196 SUBROUTINE read_coils_pass1 (iou, n_coilgroups, nmaxnodes, ngroup, &
206 INTEGER,
INTENT(in) :: iou, n_skip
207 INTEGER,
INTENT(out) :: n_coilgroups, nmaxnodes
208 INTEGER,
DIMENSION(:),
INTENT(out) :: ngroup
209 LOGICAL,
INTENT(in) :: lgrps
227 CHARACTER(200) :: line
228 CHARACTER(100) :: group_id
229 REAL(rprec) :: xw, yw, zw
230 REAL(rprec) :: currin
231 INTEGER :: i, igroup, inodes
248 rewind(iou, iostat=istat)
262 READ(iou,
'(a)',
END = 100, IOSTAT=istat) line
263 IF (istat .ne. 0)
THEN
264 WRITE(6,*)
'Problem in read_coils_pass1. istat =',istat
269 IF (line(1:3) .eq.
'end')
EXIT
281 READ(line,*,iostat=istat) xw, yw, zw, currin, igroup, group_id
282 lparsed = (istat .eq. 0)
284 i = minval(abs(igroup - ngroup(:)))
285 IF (i.ne.0 .or. lgrps)
THEN
286 n_coilgroups = n_coilgroups + 1
287 IF (n_coilgroups .gt.
SIZE(ngroup))
THEN
288 stop
' read_coils_pass1: coil groups > SIZE(ngroup)'
291 ngroup(n_coilgroups) = n_coilgroups
293 ngroup(n_coilgroups) = igroup
296 nmaxnodes = max(nmaxnodes,inodes)
304 IF (nmaxnodes .eq. 0)
THEN
312 100
IF (.not. lparsed)
THEN
313 WRITE(6,*)
'Problems in read_coils_pass1'
314 WRITE(6,*)
'EOF reached before END'
315 WRITE(6,*)
'Make sure last line of file is "end"'
318 END SUBROUTINE read_coils_pass1
323 SUBROUTINE read_coils_pass2 (iou, nmaxnodes, coil_group, ngroup, &
333 INTEGER,
INTENT(in) :: iou, n_skip
334 INTEGER,
INTENT(in) :: nmaxnodes
335 INTEGER,
DIMENSION(:),
INTENT(in) :: ngroup
336 TYPE (bsc_coilcoll),
DIMENSION(:),
INTENT(inout) :: coil_group
337 LOGICAL,
INTENT(in) :: lgrps
355 INTEGER,
DIMENSION(:) :: index1(1)
357 INTEGER :: n_coilgroups, id_group
358 INTEGER :: i, igroup, inodes, nnod, icoil
359 TYPE(bsc_coil) :: coil_temp
360 REAL(rprec),
DIMENSION(3,nmaxnodes) :: xnod_in
361 REAL(rprec) :: currin, currin_first
362 REAL(rprec) :: this_rcirc
363 REAL(rprec),
DIMENSION(3) :: this_xcent, this_enhat
364 CHARACTER :: line*200, group_id*100
365 CHARACTER(len=LEN(coil_group(1)%s_name)) :: s_name
366 CHARACTER(len=LEN(coil_group(1)%l_name)) :: l_name
386 n_coilgroups =
SIZE(coil_group)
389 DO i = 1,n_coilgroups
390 WRITE(l_name,*)
'i = ',i
391 CALL bsc_construct(coil_group(i),
'boring id',l_name)
395 rewind(iou, iostat=istat)
409 READ(iou,
'(a)',
END = 100) line
410 IF (line(1:3) .eq.
'end')
EXIT
414 READ(line,*,iostat=istat) xnod_in(1:3,inodes), currin
417 IF (inodes .eq. 1) currin_first = currin
423 READ(line,*,iostat=istat) xnod_in(1:3,inodes), currin,
425 lparsed = (istat .eq. 0)
433 id_group = id_group + 1
435 index1 = minloc(abs(igroup - ngroup(:)))
437 IF (igroup .ne. ngroup(id_group))
438 & stop
'ID_GROUP != IGROUP in coils_dot_pass2'
442 icoil = coil_group(id_group) % ncoil + 1
443 WRITE(s_name,
'(a4,i5.5)')
'ID #', icoil
449 this_xcent(1:3) = (/ zero, zero, xnod_in(3,1) /)
450 this_enhat(1:3) = (/ zero, zero, 1.0_rprec /)
451 this_rcirc = xnod_in(1,1)
452 CALL bsc_construct(coil_temp,
'fil_circ',s_name,
'',
453 & currin_first, rcirc = this_rcirc,
454 & xcent = this_xcent(1:3),enhat = this_enhat(1:3))
458 CALL bsc_construct(coil_temp,
'fil_loop',s_name,
'',
459 & currin_first,xnod_in(1:3,1:nnod))
466 CALL bsc_construct(coil_temp,
'fil_loop',s_name,
'',
467 & currin_first,xnod_in(1:3,1:nnod))
472 CALL bsc_append(coil_group(id_group),coil_temp)
475 coil_group(id_group) % s_name = trim(group_id)
476 WRITE (coil_group(id_group) % l_name,
'(a7,i6.6)')
487 100
IF (.not. lparsed)
THEN
488 WRITE(6,*)
'Problems in read_coils_pass2'
489 WRITE(6,*)
'EOF reached before END'
490 WRITE(6,*)
'Make sure last line of file is "end"'
493 END SUBROUTINE read_coils_pass2
499 SUBROUTINE bfield (rp, phi, zp, br, bp, bz, ig)
504 INTEGER,
OPTIONAL :: ig
505 REAL(rprec),
INTENT(in) :: rp, phi, zp
506 REAL(rprec),
INTENT(out) :: br, bp, bz
512 REAL(rprec),
DIMENSION(3) :: xpt, bvec
516 cosp = cos(phi); sinp = sin(phi)
522 IF (
PRESENT(ig)) igroup = ig
524 CALL bsc_b (coil_group(igroup), xpt, bvec)
527 br = bvec(1)*cosp + bvec(2)*sinp
528 bp =-bvec(1)*sinp + bvec(2)*cosp
531 END SUBROUTINE bfield
537 SUBROUTINE write_coils_file (extension)
543 CHARACTER(LEN=*) :: extension
547 INTEGER :: cunit=30, ierr, ig, ncoils, n, nwire, iwire, nextcur
548 REAL(rprec) :: current
549 CHARACTER(len=LEN(coil_group(1)%s_name)) :: g_name
554 CALL safe_open(cunit, ierr,
'coils.' // trim(extension),
555 1
'replace',
'formatted')
556 IF (ierr .ne. 0)stop
'Error opening coils-dot file in write_coils'
561 WRITE (cunit,100) nfp_bs
562 100
FORMAT(
"periods ",i2,/,
"begin filament",/,
"mirror NUL")
567 nextcur =
SIZE(coil_group)
569 ncoils = coil_group(ig) % ncoil
570 g_name = coil_group(ig) % s_name
572 current = coil_group(ig) % coils(n) % current
573 nwire =
SIZE(coil_group(ig) % coils(n) % xnod, 2)
574 IF (any(coil_group(ig) % coils(n) % xnod(:,1) .ne.
575 1 coil_group(ig) % coils(n) % xnod(:,nwire)))
576 1 print *,
'Coil did not close in WRITE_COILS_DOT for group ',
578 DO iwire = 1, nwire-1
579 WRITE(cunit,
'(1p,4e22.14)')
580 1 coil_group(ig) % coils(n) % xnod(:,iwire), current
582 WRITE(cunit,
'(1p,4e22.14,i4,1x,a)')
583 1 coil_group(ig) % coils(n) % xnod(:,nwire), zero, ig,
588 WRITE (cunit,
'(a3)')
"end"
592 END SUBROUTINE write_coils_file
598 SUBROUTINE afield (rp, phi, zp, ar, ap, az, ig)
603 INTEGER,
OPTIONAL :: ig
604 REAL(rprec),
INTENT(in) :: rp, phi, zp
605 REAL(rprec),
INTENT(out) :: ar, ap, az
611 REAL(rprec),
DIMENSION(3) :: xpt, avec
615 cosp = cos(phi); sinp = sin(phi)
621 IF (
PRESENT(ig)) igroup = ig
623 CALL bsc_a (coil_group(igroup), xpt, avec)
626 ar = avec(1)*cosp + avec(2)*sinp
627 ap =-avec(1)*sinp + avec(2)*cosp
630 END SUBROUTINE afield
636 SUBROUTINE cleanup_biotsavart
644 IF (
ALLOCATED(coil_group))
THEN
645 DO i = 1,
SIZE(coil_group)
646 CALL bsc_destroy(coil_group(i))
648 DEALLOCATE(coil_group)
651 IF (
ASSOCIATED(single_coil))
THEN
652 CALL bsc_destroy(single_coil)
653 DEALLOCATE(single_coil)
656 END SUBROUTINE cleanup_biotsavart
658 END MODULE biotsavart