From 8d75ea0d75478508b21b3471abc4c37c871ead90 Mon Sep 17 00:00:00 2001
From: Mark Driver <mdd31@cam.ac.uk>
Date: Thu, 20 Jul 2017 16:18:14 +0100
Subject: [PATCH] created script with methods for generating solvation maps
 (contour plots) from information read in from files. Added tests for methods
 that do no produce a plot.

---
 .../solvationmapgenerator.py                  |  95 ++++++++++++++
 .../solvationmapgeneratortest.py              | 124 ++++++++++++++++++
 .../test/solvationmapcreatortests.py          |   2 +
 3 files changed, 221 insertions(+)
 create mode 100644 solventmapcreator/solvationcalculation/solvationmapgenerator.py
 create mode 100644 solventmapcreator/test/solvationcalculationtest/solvationmapgeneratortest.py

diff --git a/solventmapcreator/solvationcalculation/solvationmapgenerator.py b/solventmapcreator/solvationcalculation/solvationmapgenerator.py
new file mode 100644
index 0000000..394d8fa
--- /dev/null
+++ b/solventmapcreator/solvationcalculation/solvationmapgenerator.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+Script for reading in the polynomial coefficients, and also the fractional
+occupancy, and generating the solvent Maps. Temperature and the ranges of the
+two SSIPs forthe x and y axes need to be supplied.
+
+@author: mark
+"""
+
+import logging
+import resultsanalysis.resultsoutput.plottinginput as plottinginput
+import solventmapcreator.io.polynomialdatareader as polynomialdatareader
+import solventmapcreator.solvationcalculation.fractionaloccupancycalculator as fractionaloccupancycalculator
+import solventmapcreator.solvationcalculation.solvationplotinformation as solvationplotinformation
+
+
+logging.basicConfig()
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.WARN)
+
+def create_solvation_plot(epsilon_i_list, epsilon_j_list,
+                          solvent_filename, solvent_id,
+                          polynomial_filename, polynomial_order, **kwargs):
+    """This creates and outputs the solvation plot.
+    """
+    input_data = create_plot_input_data_from_files(epsilon_i_list, epsilon_j_list,
+                                                   solvent_filename, solvent_id,
+                                                   polynomial_filename,
+                                                   polynomial_order, **kwargs)
+    return plot_and_write_contour_map(input_data, **kwargs)
+
+def plot_and_write_contour_map(input_data, **kwargs):
+    """This creates and plots a contour map wit hthe input given.
+    """
+    return plottinginput.create_and_write_contour_plot(input_data, **kwargs)
+
+def create_plot_input_data_from_files(epsilon_i_list, epsilon_j_list,
+                                      solvent_filename, solvent_id,
+                                      polynomial_filename, polynomial_order, **kwargs):
+    """This reads in the information and generates the data for plotting.
+    """
+    theta = calculate_fractional_occupancy_for_phase(solvent_filename, solvent_id, kwargs.get("soluteconcentration", 0.001))
+    polynomial_coefficients = parse_polynomial_data_file_extract_polynomial_coefficients(polynomial_filename, polynomial_order)
+    temperature = kwargs.get("temperature", 298.0)
+    x_label = kwargs.get("x_label", r"\beta")
+    y_label = kwargs.get("y_label", r"\alpha")
+    input_data = create_plot_input_data(epsilon_i_list, epsilon_j_list,
+                                        temperature, theta, polynomial_coefficients,
+                                        x_label, y_label)
+    append_output_filename_stem(input_data, solvent_id)
+    return input_data
+
+def append_output_filename_stem(plot_input_data, solvent_id):
+    """This generates the outputfilename stem for the plot, and appends it to
+    the plotting input data.
+    """
+    plot_input_data['figure_label'] = create_output_filename_stem(solvent_id)
+
+def create_output_filename_stem(solvent_id):
+    """This generates the outputfilename stem for the plot.
+    """
+    return solvent_id.replace(',', '_')
+
+def create_plot_input_data(epsilon_i_list, epsilon_j_list, temperature, theta,
+                           polynomial_coefficients, x_label, y_label):
+    """This creates a dictionary containing the input data and labels for plotting.
+    """
+    return solvationplotinformation.create_plot_input_data(epsilon_i_list,
+                                                           epsilon_j_list,
+                                                           temperature, theta,
+                                                           polynomial_coefficients,
+                                                           x_label, y_label)
+
+def calculate_fractional_occupancy_for_phase(solvent_filename, solvent_id,
+                                             solute_concentration):
+    """This calculates the fractional occupancy of the phase. This is the sum
+    of the solvent and solute contributions.
+    """
+    return fractionaloccupancycalculator.calculate_fractional_occupancy_for_phase(solvent_filename,
+                                                                                  solvent_id,
+                                                                                  solute_concentration)
+
+def parse_polynomial_data_file_extract_polynomial_coefficients(filename,
+                                                               polynomial_order):
+    """This parses a polynomial file and gets the coefficients for the given
+    polynomial order.
+    """
+    return parse_polynomial_data_file(filename)[polynomial_order]["coefficients"]
+
+def parse_polynomial_data_file(filename):
+    """This parses a polynomial data file, and extracts the information
+    relating to the polynomial fits, returning a dictionary.
+    """
+    return polynomialdatareader.parse_polynomial_data_file(filename)
diff --git a/solventmapcreator/test/solvationcalculationtest/solvationmapgeneratortest.py b/solventmapcreator/test/solvationcalculationtest/solvationmapgeneratortest.py
new file mode 100644
index 0000000..f7ae5d5
--- /dev/null
+++ b/solventmapcreator/test/solvationcalculationtest/solvationmapgeneratortest.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+Script for testing the functions in the solvationmapgenerator script
+that assemble the data. The functions that write plots are not tested.
+
+@author: mark
+"""
+
+import logging
+import unittest
+import numpy as np
+import solventmapcreator.solvationcalculation.solvationmapgenerator as solvationmapgenerator
+
+logging.basicConfig()
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.WARN)
+
+class SolvationMapGeneratorTestCase(unittest.TestCase):
+    """Test case for solvationmapgenerator tests.
+    """
+    def setUp(self):
+        """Set up before tests.
+        """
+        self.expected_data_by_solvent_id = {"expected_poly_fit":{1:{"coefficients":np.array([-0.05, 
+                                                                                             1.07142857]),
+                                                                    "RMSE":0.015430334996209221,
+                                                                    "order":1,
+                                                                    "covar":0.0007143}}}
+        self.epsilon_i_list = np.array([float(x) for x in range(3)])
+        self.epsilon_j_list = np.array([float(x) for x in range(2)])
+        
+    def tearDown(self):
+        """clean up after tests.
+        """
+        del self.expected_data_by_solvent_id
+    def test_create_plot_input_data_from_files(self):
+        """Test to see if expected dictionary is produced.
+        """
+        expected_dict = {'x_data':np.array([[0, 1, 2],[0, 1, 2]]),
+                         'y_data':np.array([[0, 0, 0], [1, 1, 1]]),
+                         'z_data':np.array([[-4.532289, -3.46086],
+                                            [-3.46086, -1.671915],
+                                            [-2.389432,  0.06058]]),
+                         "x_label":"\\beta", "y_label":"\\alpha",
+                         "plot_axis_range":((0.0, 2.0), (0.0, 1.0)),
+                         "figure_label":"water"}
+        actual_dict = solvationmapgenerator.create_plot_input_data_from_files(self.epsilon_i_list, self.epsilon_j_list,
+                                                                              "resources/watersolvent.xml", "water",
+                                                                              "resources/expected_poly_fit.csv", 1)
+        self.assertListEqual(sorted(expected_dict.keys()), sorted(actual_dict.keys()))
+        for key in expected_dict.keys():
+            if key == "plot_axis_range":
+                np.testing.assert_array_almost_equal(np.array(expected_dict[key]), np.array(actual_dict[key]))
+            elif "_data" in key:
+                np.testing.assert_array_almost_equal(expected_dict[key], actual_dict[key])
+            else:
+                self.assertEqual(expected_dict[key], actual_dict[key])
+    def test_append_output_filename_stem(self):
+        """Test to see if filename stem is appended.
+        """
+        expected_dict = {"figure_label":"water"}
+        actual_dict = {}
+        solvationmapgenerator.append_output_filename_stem(actual_dict, "water")
+        self.assertDictEqual(expected_dict, actual_dict)
+    def test_create_output_filename_stem(self):
+        """Test to see if expected file name stem is produced.
+        """
+        expected_filename_stem = "water_"
+        actual_filename_stem = solvationmapgenerator.create_output_filename_stem("water,")
+        self.assertEqual(expected_filename_stem, actual_filename_stem)
+    def test_create_plot_input_data(self):
+        """Test to see if expected input data is returned.
+        """
+        expected_dict = {'x_data':np.array([[0, 1, 2],[0, 1, 2]]),
+                         'y_data':np.array([[0, 0, 0], [1, 1, 1]]),
+                         'z_data':np.array([[-4.004792, -3.004792],
+                                            [-3.004792, -1.250065],
+                                            [-2.004792,  0.454246]]),
+                         "x_label":"x_label", "y_label":"y_label",
+                         "plot_axis_range":((0.0, 2.0), (0.0, 1.0))}
+        actual_dict = solvationmapgenerator.create_plot_input_data(self.epsilon_i_list,
+                                                                   self.epsilon_j_list,
+                                                                   298.0, 1.0,
+                                                                   np.array([0.5, 1.0]),
+                                                                   "x_label", "y_label")
+        self.assertListEqual(sorted(expected_dict.keys()), sorted(actual_dict.keys()))
+        for key in expected_dict.keys():
+            if key == "plot_axis_range":
+                np.testing.assert_array_almost_equal(np.array(expected_dict[key]), np.array(actual_dict[key]))
+            elif "_data" in key:
+                np.testing.assert_array_almost_equal(expected_dict[key], actual_dict[key])
+            else:
+                self.assertEqual(expected_dict[key], actual_dict[key])
+    def test_calculate_fractional_occupancy_for_phase(self):
+        """Test to see if expected fractional occupancy is returned.
+        """
+        expected_value = (55.35 * 4.0 /300.0) + (0.001/300)
+        actual_value = solvationmapgenerator.calculate_fractional_occupancy_for_phase("resources/watersolvent.xml",
+                                                                                      "water", 0.001)
+        self.assertAlmostEqual(expected_value, actual_value)
+    def test_parse_polynomial_data_file_extract_polynomial_coefficients(self):
+        """Test to see if expected array is returned.
+        """
+        expected_array = self.expected_data_by_solvent_id["expected_poly_fit"][1]["coefficients"]
+        actual_array = solvationmapgenerator.parse_polynomial_data_file_extract_polynomial_coefficients("resources/expected_poly_fit.csv", 1)
+        np.testing.assert_array_almost_equal(expected_array, actual_array)
+    def test_parse_polynomial_data_file(self):
+        """Test to see if expected dictionary is reutrned.
+        """
+        expected_poly_dictionary = self.expected_data_by_solvent_id["expected_poly_fit"]
+        actual_poly_dictionary = solvationmapgenerator.parse_polynomial_data_file("resources/expected_poly_fit.csv")
+        self.assertListEqual(sorted(expected_poly_dictionary.keys()), sorted(actual_poly_dictionary.keys()))
+        for poly_order in expected_poly_dictionary.keys():
+            expected_dictionary = expected_poly_dictionary[poly_order]
+            actual_dictionary = actual_poly_dictionary[poly_order]
+            self.assertListEqual(sorted(expected_dictionary.keys()), sorted(actual_dictionary.keys()))
+            for key in expected_dictionary.keys():
+                if key == "RMSE" or key == "covar":
+                    self.assertAlmostEqual(expected_dictionary[key], actual_dictionary[key])
+                elif key == "order":
+                    self.assertEqual(expected_dictionary[key], actual_dictionary[key])
+                else:
+                    np.testing.assert_array_almost_equal(expected_dictionary[key], actual_dictionary[key])
\ No newline at end of file
diff --git a/solventmapcreator/test/solvationmapcreatortests.py b/solventmapcreator/test/solvationmapcreatortests.py
index 21684a9..2655f1a 100644
--- a/solventmapcreator/test/solvationmapcreatortests.py
+++ b/solventmapcreator/test/solvationmapcreatortests.py
@@ -13,6 +13,7 @@ from solventmapcreator.test.iotest.solventxmlreadertest import SolventXMLReaderT
 from solventmapcreator.test.iotest.polynomialdatawritertest import PolynomialDataWriterTestCase
 from solventmapcreator.test.iotest.polynomialdatareadertest import PolynomialDataReaderTestCase
 from solventmapcreator.test.solvationcalculationtest.solvationcalculatortest import SolvationCalculatorTestCase
+from solventmapcreator.test.solvationcalculationtest.solvationmapgeneratortest import SolvationMapGeneratorTestCase
 from solventmapcreator.test.solvationcalculationtest.solvationplotinformationtest import SolvationPlotInformationTestCase
 from solventmapcreator.test.solvationcalculationtest.fractionaloccupancycalculatortest import FractionalOccupancyCalculatorTestCase
 from solventmapcreator.test.polynomialanalysistest.polynomialdataanalysistest import PolynomialDataAnalysisTestCase
@@ -26,6 +27,7 @@ IO_TEST_CASES = [SolvationEnergyReaderTestCase, SolventXMLReaderTestCase,
                  PolynomialDataWriterTestCase, PolynomialDataReaderTestCase]
 
 SOLVATION_CALCULATION_TEST_CASES = [SolvationCalculatorTestCase,
+                                    SolvationMapGeneratorTestCase,
                                     SolvationPlotInformationTestCase,
                                     FractionalOccupancyCalculatorTestCase]
 
-- 
GitLab