Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 29 additions & 16 deletions bmad/code/pointer_to_next_ele.f90
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
!+
! Function pointer_to_next_ele (this_ele, offset, skip_beginning, follow_fork) result (next_ele)
! Function pointer_to_next_ele (this_ele, offset, skip_beginning, follow_fork, ix_multipass) result (next_ele)
!
! Function to return a pointer to the next (if offset = 1) tracking element relative to this_ele.
!
! If the this_ele is a super_lord element, the appropriate element in the tracking
! If the this_ele is a super_lord or girder_lord, the appropriate element in the tracking
! part of the lattice is returned.
!
! If this_ele is a lord element but not a super_lord then this is an error since
! If this_ele is a lord element but not a super_lord nor a girder_lord then this is an error since
! it is not clear what to do in this case.
!
! This routine will always wrap around between branch end and branch beginning
Expand All @@ -26,12 +26,15 @@
! when wrapping around. Default is False.
! follow_fork -- logical, optional: If True then fork at any fork element.
! Default is False.
!
! ix_multipass -- integer, optional: Default = 1. Used to select the multipass branch if
! this_ele is a multipass_lord.
!
! Output:
! next_ele -- ele_struct, pointer: Element after this_ele (if offset = 1).
! Nullified if there is an error. EG bad this_ele.
!-

function pointer_to_next_ele (this_ele, offset, skip_beginning, follow_fork) result (next_ele)
function pointer_to_next_ele (this_ele, offset, skip_beginning, follow_fork, ix_multipass) result (next_ele)

use bmad_routine_interface, dummy => pointer_to_next_ele

Expand All @@ -42,7 +45,7 @@ function pointer_to_next_ele (this_ele, offset, skip_beginning, follow_fork) res
type (ele_struct), pointer :: an_ele
type (branch_struct), pointer :: branch

integer, optional :: offset
integer, optional :: offset, ix_multipass
integer i, ix_ele, n_off
logical, optional :: skip_beginning, follow_fork

Expand All @@ -65,16 +68,26 @@ function pointer_to_next_ele (this_ele, offset, skip_beginning, follow_fork) res
! Initially point to the first or last slave element so that this routine
! will return a pointer to an element that is not a slave of this_ele.

if (this_ele%ix_ele > this_ele%branch%n_ele_track) then ! Is a lord
if (this_ele%lord_status /= super_lord$) return ! Error
if (n_off > 0) then
an_ele => pointer_to_slave(this_ele, this_ele%n_slave)
else
an_ele => pointer_to_slave(this_ele, 1)
endif
else
an_ele => this_ele
endif
an_ele => this_ele

do
if (an_ele%ix_ele <= an_ele%branch%n_ele_track) exit ! Is not a lord

select case (an_ele%lord_status)
case (multipass_lord$)
an_ele => pointer_to_slave(an_ele, integer_option(1, ix_multipass))

case (super_lord$, girder_lord$)
if (n_off > 0) then
an_ele => pointer_to_slave(an_ele, an_ele%n_slave)
else
an_ele => pointer_to_slave(an_ele, 1)
endif

case default
return ! Error
end select
enddo

! Apply offset.
! If follow_fork = True then must check all elements in between for a possible fork element.
Expand Down
4 changes: 2 additions & 2 deletions bmad/modules/bmad_routine_interface.f90
Original file line number Diff line number Diff line change
Expand Up @@ -2189,12 +2189,12 @@ function pointer_to_multipass_lord (ele, ix_pass, super_lord) result (multi_lord
type (ele_struct), pointer, optional :: super_lord
end function

function pointer_to_next_ele (this_ele, offset, skip_beginning, follow_fork) result (next_ele)
function pointer_to_next_ele (this_ele, offset, skip_beginning, follow_fork, ix_multipass) result (next_ele)
import
implicit none
type (ele_struct), target :: this_ele
type (ele_struct), pointer :: next_ele
integer, optional :: offset
integer, optional :: offset, ix_multipass
logical, optional :: skip_beginning, follow_fork
end function

Expand Down
8 changes: 5 additions & 3 deletions bmad/parsing/bmad_parser_mod.f90
Original file line number Diff line number Diff line change
Expand Up @@ -1622,11 +1622,13 @@ subroutine parser_read_sr_wake (ele, delim, delim_found, err_flag)
srz%smoothing_sigma = c_light * srz%smoothing_sigma
endif

if (srz%smoothing_sigma /= 0) then
ns = max(1, nint(3*srz%smoothing_sigma / srz%dz))
f = srz%smoothing_sigma / srz%dz
ns = nint(3.0_rp * f)

if (ns /= 0) then
allocate (gauss(-ns:ns))
do i = -ns, ns
gauss(i) = exp(-0.5 * i * (srz%dz / srz%smoothing_sigma)**2)
gauss(i) = exp(-0.5_rp * i / f**2)
enddo

srz%fw = 0
Expand Down
27 changes: 22 additions & 5 deletions regression_tests/multipass_test/multipass_test.f90
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ program multipass_test
implicit none

type (lat_struct), target :: lat, lat2
type (ele_struct), pointer :: ele, ele2, lord
type (ele_struct), pointer :: ele, ele0, ele2, lord, ele3, ele4
type (ele_pointer_struct), allocatable :: eles(:)
type (rf_stair_step_struct), pointer :: step

Expand All @@ -16,6 +16,26 @@ program multipass_test

open (1, file = 'output.now')

! Girder and multipass

call bmad_parser ('multipass_with_girder.bmad', lat)
do ie = 1, lat%n_ele_track
ele => lat%ele(ie)
ele0 => pointer_to_next_ele(ele, -1)
ele2 => pointer_to_next_ele(ele, 1)
write (1, '(3a)') quote(ele%name), ' STR ', quote(trim(ele0%name) // ' + ' // trim(ele2%name))
enddo

do ie = lat%n_ele_track+1, lat%n_ele_max
ele => lat%ele(ie)
ele0 => pointer_to_next_ele(ele, -1)
ele2 => pointer_to_next_ele(ele, 1)
ele3 => pointer_to_next_ele(ele, -1, ix_multipass = 2)
ele4 => pointer_to_next_ele(ele, 1, ix_multipass = 2)
write (1, '(3a)') quote(ele%name), ' STR ', quote(trim(ele0%name) // ' + ' // trim(ele2%name) // &
' + ' // trim(ele3%name) // ' + ' // trim(ele4%name))
enddo

! Space_charge_method test

call bmad_parser ('multipass_and_superimpose.bmad', lat)
Expand All @@ -33,7 +53,6 @@ program multipass_test
call lat_ele_locator('CAVITY1', lat, eles, n_loc)
lord => eles(1)%ele


do is = 0, 2
if (is == 0) then
ele => lord
Expand All @@ -52,8 +71,6 @@ program multipass_test
ele => eles(1)%ele
write (1, '(a, 2es22.14)') '"END-energy" REL 1E-8', ele%value(p0c$), ele%value(E_tot$)



! Forking with a branch element

call bmad_parser ('branch_fork.bmad', lat)
Expand Down Expand Up @@ -83,7 +100,7 @@ program multipass_test
write (1, '(3a)') '"MS-12" STR "', trim(lat%ele(12)%name), '"'
write (1, '(3a)') '"MS-13" STR "', trim(lat%ele(13)%name), '"'

! fiducial and flexible patch
! Fiducial and flexible patch

call bmad_parser ('patch.bmad', lat)
call write_bmad_lattice_file ('lat_out2.bmad', lat)
Expand Down
19 changes: 19 additions & 0 deletions regression_tests/multipass_test/multipass_with_girder.bmad
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
no_digested

beginning[beta_a] = 1
beginning[beta_b] = 1
beginning[e_tot] = 100e6
parameter[geometry] = open

f = 0
p1: sbend, L = 1, angle = pi/2 * f, ref_tilt = pi/2
p2: sbend, L = 2, angle = pi/2 * f
g1: girder = {p1, p2}, x_offset = 0.001

lat: line[multipass] = (p1, p2)
lat2: line = (lat, lat)
use, lat2

m1: marker, superimpose, ref = p1


15 changes: 15 additions & 0 deletions regression_tests/multipass_test/output.correct
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
"P1\1#1" STR "BEGINNING + M1\1"
"M1\1" STR "P1\1#1 + P1\1#2"
"P1\1#2" STR "M1\1 + P2\1"
"P2\1" STR "P1\1#2 + P1\2#1"
"P1\2#1" STR "P2\1 + M1\2"
"M1\2" STR "P1\2#1 + P1\2#2"
"P1\2#2" STR "M1\2 + P2\2"
"P2\2" STR "P1\2#2 + END"
"END" STR "P2\2 + BEGINNING"
"P1\1" STR "BEGINNING + P2\1 + BEGINNING + P2\1"
"P1\2" STR "P2\1 + P2\2 + P2\1 + P2\2"
"M1" STR "P1\1#1 + P1\1#2 + P1\2#1 + P1\2#2"
"P2" STR "P1\1#2 + P1\2#1 + P1\2#2 + END"
"P1" STR "BEGINNING + P2\1 + P2\1 + P2\2"
"G1" STR "BEGINNING + P1\2#1 + P2\1 + END"
"scm-1DRI01\1#1" STR "Slice" "Slice"
"ref_time-1" ABS 1E-16 5.82081208740982E-09
"scm-2DRI01\1\Q01\1" STR "FFT_3D" "FFT_3D"
Expand Down
44 changes: 22 additions & 22 deletions regression_tests/tao_color_test/output.correct
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
"css4_name" STR teal
"css4_name_mixed_case" STR teal
"css4_name_upper" STR teal
"css4_name_salmon" STR salmon
"css4_name_gold" STR gold
"original_name" STR red
"original_name_blue" STR blue
"original_name_upper" STR red
"hex_6digit" STR #FF5733
"hex_6digit_lower" STR #FF5733
"hex_6digit_mixed" STR #FF5733
"hex_3digit" STR #F53
"hex_3digit_lower" STR #ABC
"rgb_format" STR RGB(0,128,255)
"rgb_format_spaces" STR RGB(255,0,128)
"rgb_lower_prefix" STR RGB(10,20,30)
"rgb_mixed_prefix" STR RGB(1,2,3)
"rgb_four_values" STR True
"invalid_color_rejected" STR True
"label_color_css4" STR teal
"label_color_upper" STR gold
"label_color_hex" STR #FF0000
"css4_name" STR "teal"
"css4_name_mixed_case" STR "teal"
"css4_name_upper" STR "teal"
"css4_name_salmon" STR "salmon"
"css4_name_gold" STR "gold"
"original_name" STR "red"
"original_name_blue" STR "blue"
"original_name_upper" STR "red"
"hex_6digit" STR "#FF5733"
"hex_6digit_lower" STR "#FF5733"
"hex_6digit_mixed" STR "#FF5733"
"hex_3digit" STR "#F53"
"hex_3digit_lower" STR "#ABC"
"rgb_format" STR "RGB(0,128,255)"
"rgb_format_spaces" STR "RGB(255,0,128)"
"rgb_lower_prefix" STR "RGB(10,20,30)"
"rgb_mixed_prefix" STR "RGB(1,2,3)"
"rgb_four_values" STR "True"
"invalid_color_rejected" STR "True"
"label_color_css4" STR "teal"
"label_color_upper" STR "gold"
"label_color_hex" STR "#FF0000"
12 changes: 6 additions & 6 deletions regression_tests/tao_color_test/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,19 +67,19 @@

if expected is None:
# Expect rejection (error message)
results.append(f'"{label}" STR {has_error}')
results.append(f'"{label}" STR "{has_error}"')
elif has_error:
results.append(f'"{label}" STR ERROR')
results.append(f'"{label}" STR "ERROR"')
else:
results.append(f'"{label}" STR {actual}')
results.append(f'"{label}" STR "{actual}"')

# Test that an invalid color produces an error (doesn't crash)
cmd = f"set curve {curve} line%color = not_a_color;quit"
exe = f'{bin_dir}tao -noplot -lat {lat_file} -command "{cmd}"'
proc = subprocess.run(exe, shell=True, capture_output=True, text=True)
# Should get an error message but not crash (exit 0)
has_error_msg = "ERROR" in proc.stdout
results.append(f'"invalid_color_rejected" STR {has_error_msg}')
results.append(f'"invalid_color_rejected" STR "{has_error_msg}"')

# Test label_color via python plot_graph command
label_color_tests = [
Expand Down Expand Up @@ -109,9 +109,9 @@

has_error = "[ERROR" in proc.stdout or proc.returncode != 0
if has_error:
results.append(f'"{label}" STR ERROR')
results.append(f'"{label}" STR "ERROR"')
else:
results.append(f'"{label}" STR {actual}')
results.append(f'"{label}" STR "{actual}"')

# Write output.now
with open("output.now", "w") as f:
Expand Down
2 changes: 1 addition & 1 deletion tao/version/tao_version_mod.f90
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
!-

module tao_version_mod
character(*), parameter :: tao_version_date = "2026/06/06 15:26:06"
character(*), parameter :: tao_version_date = "2026/06/10 21:41:51"
end module
Loading