/*************************************************************************
*  Copyright (C) 2006 by luc scholtes                                    *
*  luc.scholtes@hmg.inpg.fr                                              *
*                                                                        *
*  This program is free software; it is licensed under the terms of the  *
*  GNU General Public License v2 or later. See file LICENSE for details. *
*************************************************************************/

#include "CapillaryStressRecorder.hpp"
#include <lib/high-precision/Constants.hpp>
#include <pkg/common/ElastMat.hpp>
#include <pkg/common/Sphere.hpp>
#include <pkg/dem/CapillaryPhys.hpp>
#include <pkg/dem/Law2_ScGeom_CapillaryPhys_Capillarity.hpp>
#include <pkg/dem/TriaxialCompressionEngine.hpp>

#include <core/Omega.hpp>
#include <core/Scene.hpp>

namespace yade { // Cannot have #include directive inside.

YADE_PLUGIN((CapillaryStressRecorder));
CREATE_LOGGER(CapillaryStressRecorder);

void CapillaryStressRecorder::action()
{
	shared_ptr<BodyContainer>& bodies = scene->bodies;

	// at the beginning of the file; write column titles
	if (out.tellp() == 0) { out << "iteration Scap11 Scap22 Scap33 Scap12 Scap13 Scap23 Uc Sr w" << endl; }
	if (!triaxialCompressionEngine) {
		vector<shared_ptr<Engine>>::iterator itFirst = scene->engines.begin();
		vector<shared_ptr<Engine>>::iterator itLast  = scene->engines.end();
		for (; itFirst != itLast; ++itFirst) {
			if ((*itFirst)->getClassName() == "TriaxialCompressionEngine") {
				LOG_DEBUG("stress controller engine found");
				triaxialCompressionEngine = YADE_PTR_CAST<TriaxialCompressionEngine>(*itFirst);
			}
		}
		if (!triaxialCompressionEngine) {
			LOG_ERROR("Stress controller engine not found, the recorder cannot be used.");
			return;
		}
	}

	Real f1_cap_x = 0, f1_cap_y = 0, f1_cap_z = 0, x1 = 0, y1 = 0, z1 = 0, x2 = 0, y2 = 0, z2 = 0;
	Real sig11_cap = 0, sig22_cap = 0, sig33_cap = 0, sig12_cap = 0, sig13_cap = 0, sig23_cap = 0, Vwater = 0, capillaryPressure = 0;
	int  j = 0;

	InteractionContainer::iterator ii    = scene->interactions->begin();
	InteractionContainer::iterator iiEnd = scene->interactions->end();
	for (; ii != iiEnd; ++ii) {
		if ((*ii)->isReal()) {
			const shared_ptr<Interaction>& interaction = *ii;

			CapillaryPhys* meniscusParameters = static_cast<CapillaryPhys*>(interaction->phys.get());

			if (meniscusParameters->meniscus) {
				j = j + 1;

				unsigned int id1 = interaction->getId1();
				unsigned int id2 = interaction->getId2();

				Vector3r fcap = meniscusParameters->fCap;

				f1_cap_x = fcap[0];
				f1_cap_y = fcap[1];
				f1_cap_z = fcap[2];

				Body* de1 = (*bodies)[id1].get();
				Body* de2 = (*bodies)[id2].get();

				x1 = de1->state->pos[0];
				y1 = de1->state->pos[1];
				z1 = de1->state->pos[2];
				x2 = de2->state->pos[0];
				y2 = de2->state->pos[1];
				z2 = de2->state->pos[2];

				/// capillary stresses from contact forces

				sig11_cap = sig11_cap + f1_cap_x * (x1 - x2);
				sig22_cap = sig22_cap + f1_cap_y * (y1 - y2);
				sig33_cap = sig33_cap + f1_cap_z * (z1 - z2);
				sig12_cap = sig12_cap + f1_cap_x * (y1 - y2);
				sig13_cap = sig13_cap + f1_cap_x * (z1 - z2);
				sig23_cap = sig23_cap + f1_cap_y * (z1 - z2);

				/// Liquid volume

				Vwater += meniscusParameters->vMeniscus;
				capillaryPressure = meniscusParameters->capillaryPressure;
			}
		}
	}

	/// Sample volume

	Real V = (triaxialCompressionEngine->height) * (triaxialCompressionEngine->width) * (triaxialCompressionEngine->depth);

	/// Solid volume
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpragmas"
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
// silence the warning that SR is only written to, but never read from, and therefore useless.
	Real Vs = 0, Rbody = 0, SR = 0;
#pragma GCC diagnostic pop

	for (const auto& b : *bodies) {
		if (b->shape->getClassIndex() != Sphere::getClassIndexStatic()) continue;
		Sphere* sphere = static_cast<Sphere*>(b->shape.get());

		if (sphere) {
			Rbody = sphere->radius;
			SR += Rbody;
			Vs += 1.333 * Mathr::PI * (Rbody * Rbody * Rbody);
		}
	}

	Real Vv = V - Vs;
	Real Sr = 100 * Vwater / Vv;
	if (Sr > 100) Sr = 100;
	Real w = 100 * Vwater / V;
	if (w > (100 * Vv / V)) w = 100 * (Vv / V);

	/// homogeneized capillary stresses

	Real SIG_11_cap = 0, SIG_22_cap = 0, SIG_33_cap = 0, SIG_12_cap = 0, SIG_13_cap = 0, SIG_23_cap = 0;

	SIG_11_cap = sig11_cap / V;
	SIG_22_cap = sig22_cap / V;
	SIG_33_cap = sig33_cap / V;
	SIG_12_cap = sig12_cap / V;
	SIG_13_cap = sig13_cap / V;
	SIG_23_cap = sig23_cap / V;

	out << boost::lexical_cast<string>(scene->iter) << " " << boost::lexical_cast<string>(SIG_11_cap) << " " << boost::lexical_cast<string>(SIG_22_cap)
	    << " " << boost::lexical_cast<string>(SIG_33_cap) << " " << boost::lexical_cast<string>(SIG_12_cap) << " "
	    << boost::lexical_cast<string>(SIG_13_cap) << " " << boost::lexical_cast<string>(SIG_23_cap) << "   "
	    << boost::lexical_cast<string>(capillaryPressure) << " " << boost::lexical_cast<string>(Sr) << " " << boost::lexical_cast<string>(w) << " " << endl;
}

} // namespace yade
