(in-package :clf)

(defun march (grid &key output-every-step output-every-time
		     finish-time finish-step finish-convergence
		     print-out-border suppress-export
		     (method :kurganov-tadmor-explicit)
		     (cu nil))
  ;; Проверка начальных условий и вывод информации о процессе
  (format t "Маршевая функция запущена.~%")
  (when output-every-step
    (format t "Вывод каждые ~d итераций.~%" output-every-step))
  (when output-every-time
    (format t "Вывод каждые ~a секунд.~%" output-every-time))
  (unless (or finish-step finish-time finish-convergence)
    (error "По крайней мере одно условие остановки должно быть указано"))
  (when finish-step
    (format t "Остановка после ~d итераций.~%" finish-step))
  (when finish-time
    (format t "Остановка после ~a секунд.~%" finish-time))
  (when finish-convergence
    (format t "Остановка при невязке ~a~%" finish-convergence))

  (let ((stop-flag nil)
	(newgrid (clone grid)))
    
    ;; сначала экспортируем начальное поле
    (export-grid grid :print-out-border print-out-border)
    ;; если finish-step установлен в 0, то больше ничего не делаем
    (when (and finish-step (<= finish-step 0))
      (setf stop-flag t))
    (loop until stop-flag do
	 (update-gradients grid)
	 (let* ((print-flag nil)
		(time (grid-time grid))
		(tau (max-timestep grid method cu))
		(iterations (iteration grid)))
	   ;; изменяем шаг по времени, если надо делать вывод в
	   ;; определённый момент
	   (when output-every-time
	     ;; гарантируем, что не перескочим сразу несколько
	     ;; моментов для вывода по времени
	     (when (> tau output-every-time)
	       (setf tau output-every-time))
	     ;; условие перехода через момент времени, когда мы
	     ;; обязаны сделать вывод
	     (when (< (mod (+ time tau) output-every-time)
		      (mod time output-every-time))
	       (decf tau (mod (+ time tau) output-every-time))
	       (setf print-flag t))
	     )
	   ;; изменяем шаг по времени, если близки ко времени
	   ;; окончанию расчёта
	   (when (and finish-time
		      (> (+ time tau) finish-time))
	     (setf tau (- finish-time time))
	     (setf print-flag t)
	     (setf stop-flag t))
	   ;; проверяем, не надо ли делать вывод после этой итерации
	   (when (and output-every-step
		      (zerop (mod (1+ iterations) output-every-step)))
	     (setf print-flag t))
	   ;; проверяем, является ли следующий шаг последним
	   (when (and finish-step
		      (>= (1+ iterations) finish-step))
	     (setf print-flag t)
	     (setf stop-flag t))
	   
	   ;; шаг
	   (format t "Iter: ~d, Tau: ~d, Time: ~d" iterations tau time)
	   (when finish-convergence (format t ", Convergence: ~d" (convergence grid)))
	   (newline)
	   (make-step grid newgrid tau method)
	   
	   ;; заботимся о выставлении параметров сетки
	   (incf (iteration newgrid))
	   (incf (grid-time newgrid) tau)

	   ;; проверяем, достигли ли мы необходимой для остановки расчёта невязки
	   (count-convergence grid newgrid)
	   (when (and finish-convergence
		      (< (convergence newgrid) finish-convergence))
	     (format t "Достигнута сходимость по невзяке. Остановка.~%")
	     (format t "Невязка сетки: ~a~%Требуемая невязка: ~a~%" (convergence newgrid) finish-convergence)
	     (setf print-flag t)
	     (setf stop-flag t))

	   ;; печать
	   (when (and (not suppress-export)
		      print-flag)
	     (export-grid newgrid :print-out-border print-out-border))
	   
	   ;; меняем сетки местами
	   (setf grid (clone newgrid))

	   ))

    (when (>= *debug-level* 10)
      (format t "10: final grid~%")
      (print-grid newgrid :print-out-border t)
      (format t "----~%~%"))
    
    ;; по завершении маршевой функции возвращаем последнюю полученную сетку
    grid
    ))