You have to be very careful with the sorting field, if for some reason there is a typo or error, it just defaults to moddate. So it may seem as if you are sorting but not.
It does not throw an error.
The field you are sorting on must have the 'indexed' option set in the structure definition - and then you MUST reindex that before you will see any results.
Lastly, the sort is clumsy. It is not case insensitive, which is why Jameson suggested you use the raw field.
Basically, if you can't get it to work as you need it to, you should use the $sorter.sort tool...
Which will give you fine control over your sorting (and does not require the index field being set, it just works with the raw content).
You would do something like:
#set ($bachunsorted= $dotcontent.pull("+contentType:ProgramsOfStudy +(ProgramsOfStudy.type:*UG*)",0, "modDate desc"))
#foreach ($bach in $sorter.sort($bachunsorted,"title"))