CntrlComparison parsing

This commit is contained in:
2015-12-04 10:15:51 -05:00
parent 4d46f206ac
commit 685e8c8658
39 changed files with 820 additions and 491 deletions
+17 -6
View File
@@ -43,24 +43,35 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Parsers\CntrlComparisonParserTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Services\LeafInputCsvParserTests.cs" /> <Compile Include="Parsers\LeafInputCsvParserTests.cs" />
<Compile Include="Parsers\CurveDataListTests.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="packages.config" /> <None Include="packages.config" />
<Content Include="Services\LeafInputData\LeafInput-valid.csv"> <Content Include="Parsers\LeafInputData\LeafInput-valid.csv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
<Content Include="Services\LeafInputData\LeafInput-titlesRemoved.csv"> <Content Include="Parsers\LeafInputData\LeafInput-titlesRemoved.csv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
<Content Include="Services\LeafInputData\LeafInput-incompleteRows.csv"> <Content Include="Parsers\LeafInputData\LeafInput-incompleteRows.csv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
<Content Include="Services\LeafInputData\LeafInput-noData.csv"> <Content Include="Parsers\LeafInputData\LeafInput-noData.csv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="Parsers\LeafInputData\LeafInput-tabSeparated.csv" />
<Content Include="Parsers\LeafOutputData\cntrlbestparameters_Wild Capsicum.csv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Parsers\LeafOutputData\cntrlcomparison_Wild Capsicum.csv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Parsers\LeafOutputData\cntrlparameters_Wild Capsicum.csv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
<None Include="Services\LeafInputData\LeafInput-tabSeparated.csv" />
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup />
<ItemGroup> <ItemGroup>
+1
View File
@@ -1,2 +1,3 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=parsers_005Cleafinputdata/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=Services_005CLeafInputData/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=Services_005CLeafInputData/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using LeafWeb.Core.Models;
using LeafWeb.Core.Parsers;
using NUnit.Framework;
namespace LeafWeb.Core.Tests.Parsers
{
[TestFixture]
public class CntrlComparisonParserTests
{
protected const string ContentDirectory = @"Parsers\LeafOutputData\";
private static FileInfo GetContentFile(string fileName)
{
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ContentDirectory);
return new FileInfo(path + fileName);
}
[Test]
public void Parse_Valid()
{
var fileInfo = GetContentFile("cntrlcomparison_Wild Capsicum.csv");
CntrlComparison[] cntrlComparison;
using (var parser = new CntrlComparisonParser(fileInfo))
cntrlComparison = parser.Parse();
Assert.That(cntrlComparison.Length, Is.EqualTo(7 * 4));
}
}
}
+31
View File
@@ -0,0 +1,31 @@
using System;
using System.IO;
using LeafWeb.Core.Charter;
using NUnit.Framework;
namespace LeafWeb.Core.Tests.Parsers
{
[TestFixture]
public class CurveDataListTests
{
protected const string ContentDirectory = @"Services\LeafOutputData\";
private static FileInfo GetContentFile(string fileName)
{
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ContentDirectory);
return new FileInfo(path + fileName);
}
[Test]
public void Parse_Valid()
{
var fileInfo = GetContentFile("cntrlcomparison_Wild Capsicum.csv");
var cntrlComparison = new CurveDataList();
using (var reader = fileInfo.OpenText())
{
cntrlComparison.ReadFromStream(reader);
}
Assert.That(cntrlComparison.CurveData.Count, Is.EqualTo(7));
}
}
}
@@ -3,15 +3,16 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using LeafWeb.Core.Models; using LeafWeb.Core.Models;
using LeafWeb.Core.Services; using LeafWeb.Core.Parsers;
using LeafWeb.Core.Utility;
using NUnit.Framework; using NUnit.Framework;
namespace LeafWeb.Core.Tests.Services namespace LeafWeb.Core.Tests.Parsers
{ {
[TestFixture] [TestFixture]
public class LeafInputCsvParserTests public class LeafInputCsvParserTests
{ {
protected const string ContentDirectory = @"Services\LeafInputData\"; protected const string ContentDirectory = @"Parsers\LeafInputData\";
private static FileInfo GetContentFile(string fileName) private static FileInfo GetContentFile(string fileName)
{ {
@@ -1,23 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NUnit.Framework;
namespace LeafWeb.Core.Tests.Services
{
[TestFixture]
public class CntrlComparisonCsvParserTests
{
protected const string ContentDirectory = @"Services\LeafOutputData\";
private static FileInfo GetContentFile(string fileName)
{
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ContentDirectory);
return new FileInfo(path + fileName);
}
}
}
+37
View File
@@ -0,0 +1,37 @@
using System.IO;
namespace LeafWeb.Core.Charter
{
public class CurveData
{
private readonly string _curveId;
public string CurveId => _curveId;
// 1
public CurveParamSet FixedCndFixedCmp { get; }
// 2
public CurveParamSet FixedCndEstimatedCmp { get; }
// 3
public CurveParamSet EstimatedCndFixedCmp { get; }
// 4
public CurveParamSet EstimatedCndEstimatedCmp { get; }
public CurveData(TextReader sr, ref int lineNbr)
{
// For each curve in the output file there are four sets of data.
FixedCndFixedCmp = new CurveParamSet(sr, ref lineNbr, ref _curveId);
FixedCndEstimatedCmp = new CurveParamSet(sr, ref lineNbr, ref _curveId);
EstimatedCndFixedCmp = new CurveParamSet(sr, ref lineNbr, ref _curveId);
EstimatedCndEstimatedCmp = new CurveParamSet(sr, ref lineNbr, ref _curveId);
}
}
}
+42
View File
@@ -0,0 +1,42 @@
using System.Collections.Generic;
using System.IO;
namespace LeafWeb.Core.Charter
{
public class CurveDataList
{
// Each element will be a PiscalCurve element that contains
// all of the output data for one curve.
public List<CurveData> CurveData { get; }
public CurveDataList()
{
CurveData = new List<CurveData>();
}
public bool ReadFromStream(StreamReader sr)
{
// Skip the first two lines.
sr.ReadLine();
sr.ReadLine();
var lineNbr = 2;
// Now, there should be one or more rows, delimited by a row that has
// CO2i in the first field. Read in all of these rows. The first field
// in each row is the curve ID (input filename).
var more = true;
while (more)
{
var curve = new CurveData(sr, ref lineNbr);
CurveData.Add(curve);
if (sr.EndOfStream)
more = false;
}
return true;
}
}
}
+166
View File
@@ -0,0 +1,166 @@
using System.Collections.Generic;
using System.IO;
using LeafWeb.Core.Utility;
namespace LeafWeb.Core.Charter
{
public class CurveParamSet
{
public List<XyPoint> AnetMeasChloro1Data { get; } = new List<XyPoint>(); // y=AnetMeas column, x=PCO2c, for PointLimitType=1
public List<XyPoint> AnetMeasChloro2Data { get; } = new List<XyPoint>(); // y=AnetMeas column, x=PCO2c, for PointLimitType=2
public List<XyPoint> AnetMeasChloro3Data { get; } = new List<XyPoint>(); // y=AnetMeas column, x=PCO2c, for PointLimitType=3
public List<XyPoint> AnetMeasInter1Data { get; } = new List<XyPoint>(); // y=AnetMeas column, x=PCO2i, for PointLimitType=1
public List<XyPoint> AnetMeasInter2Data { get; } = new List<XyPoint>(); // y=AnetMeas column, x=PCO2i, for PointLimitType=2
public List<XyPoint> AnetMeasInter3Data { get; } = new List<XyPoint>(); // y=AnetMeas column, x=PCO2i, for PointLimitType=3
public List<XyPoint> AcChloroData { get; } = new List<XyPoint>();
public List<XyPoint> AjChloroData { get; } = new List<XyPoint>();
public List<XyPoint> AtChloroData { get; } = new List<XyPoint>();
public List<XyPoint> AcInterData { get; } = new List<XyPoint>();
public List<XyPoint> AjInterData { get; } = new List<XyPoint>();
public List<XyPoint> AtInterData { get; } = new List<XyPoint>();
public CurveParamSet(TextReader sr, ref int lineNbr, ref string curveId)
{
bool curveIdSet = false, doneWithAnet = false;
string line;
List<string> phrases;
while (!doneWithAnet)
{
lineNbr++;
line = sr.ReadLine();
if (line == null)
{
throw new ParseException("Unexpected end-of-file at line " + lineNbr);
}
phrases = SplitCsvLine(line);
var firstField = phrases[0];
if (firstField.Equals("CO2i"))
{
doneWithAnet = true;
}
else
{
// The fields on the line:
// Column Name
// 0 CurveID
// 1 ChlFlUse
// 2 FitGi
// 3 FitGamma
// 4 FitKco
// 5 FitRd
// 6 FitAlpha
// 7 LimitCombina
// 8 PCO2i
// 9 PCO2c
// 10 AnetMeas
// 11 AnetCal
// 12 weitedrms
// 13 PointLimitType
if (!curveIdSet)
{
curveId = firstField;
curveIdSet = true;
}
var xyPoint1 = new XyPoint(phrases[9], phrases[10]); // AnetMeas(y), PCO2c(x)
var xyPoint2 = new XyPoint(phrases[8], phrases[10]);
var pointLimitType = int.Parse(phrases[13]);
switch (pointLimitType)
{
case 1:
AnetMeasChloro1Data.Add(xyPoint1);
AnetMeasInter1Data.Add(xyPoint2);
break;
case 2:
AnetMeasChloro2Data.Add(xyPoint1);
AnetMeasInter2Data.Add(xyPoint2);
break;
case 3:
AnetMeasChloro3Data.Add(xyPoint1);
AnetMeasInter3Data.Add(xyPoint2);
break;
}
}
}
// The next set of lines will have three pairs of x,y-coordinates to save.
// A blank line signals the end of the data.
var moreData = true;
while (moreData)
{
// The fields on the line:
// Column Name
// 0 CO2i
// 1 CO2cc
// 2 Ac
// 3 CO2cj
// 4 Aj
// 5 CO2ct
// 6 At
lineNbr++;
line = sr.ReadLine();
if (line == null)
{
throw new ParseException("Unexpected end-of-file at line " + lineNbr);
}
if (line.Length == 0)
moreData = false;
else
{
phrases = SplitCsvLine(line);
var xyPoint1 = new XyPoint(phrases[1],phrases[2]); // Ac(y),CO2cc(x)
if (xyPoint1.YIsInRange(-20.0, 50.0))
AcChloroData.Add(xyPoint1);
xyPoint1 = new XyPoint(phrases[3], phrases[4]); // Aj(y),CO2cj(x)
if (xyPoint1.YIsInRange(-20.0, 50.0))
AjChloroData.Add(xyPoint1);
xyPoint1 = new XyPoint(phrases[5], phrases[6]); // At(y),CO2ct(x)
if (xyPoint1.YIsInRange(-20.0, 50.0))
AtChloroData.Add(xyPoint1);
xyPoint1 = new XyPoint(phrases[0], phrases[2]); // Ac(y),CO2i(x)
if (xyPoint1.YIsInRange(-20.0, 50.0))
AcInterData.Add(xyPoint1);
xyPoint1 = new XyPoint(phrases[0], phrases[4]); // Aj(y),CO2i(x)
if (xyPoint1.YIsInRange(-20.0, 50.0))
AjInterData.Add(xyPoint1);
xyPoint1 = new XyPoint(phrases[0], phrases[6]); // At(y),CO2i(x)
if (xyPoint1.YIsInRange(-20.0, 50.0))
AtInterData.Add(xyPoint1);
}
}
}
/// <summary>
/// This method assumes that the argument is a comma-, blank-, or
/// tab-separated set of strings. It returns an ArrayList of those
/// quantities. Consecutive commas will be returned as an empty string,
/// but all empty strings at the end of the line will be thrown away.
/// </summary>
/// <param name="line"></param>
/// <returns></returns>
private static List<string> SplitCsvLine(string line)
{
int i;
var separator = new [] {',', ' ', '\t'};
var phrases = line.Split(separator);
var retPhrases = new List<string>();
for (i = 0; i < phrases.Length; i++)
{
var phrase = phrases[i].Trim();
if (phrase.Length > 0)
retPhrases.Add(phrase);
}
return retPhrases;
}
}
}
@@ -1,14 +1,11 @@
using System; namespace LeafWeb.Core.Charter
namespace LeafWeb.Core.Models
{ {
[Serializable]
public class XyPoint public class XyPoint
{ {
public XyPoint(String x, String y) public XyPoint(string x, string y)
{ {
X = Double.Parse(x); X = double.Parse(x);
Y = Double.Parse(y); Y = double.Parse(y);
} }
public double X { get; private set; } public double X { get; private set; }
+14 -4
View File
@@ -56,16 +56,26 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Models\CntrlComparison.cs" />
<Compile Include="Models\CntrlComparisonFittingInfo.cs" />
<Compile Include="Models\CntrlComparisonPhotosyntheticInfo.cs" />
<Compile Include="Charter\CurveDataList.cs" />
<Compile Include="Charter\CurveData.cs" />
<Compile Include="Charter\CurveParamSet.cs" />
<Compile Include="Models\LeafInput.cs" /> <Compile Include="Models\LeafInput.cs" />
<Compile Include="Models\LeafInputData.cs" /> <Compile Include="Models\LeafInputData.cs" />
<Compile Include="Models\LeafInputFile.cs" /> <Compile Include="Models\LeafInputFile.cs" />
<Compile Include="Models\LeafInputPhotosynthetic.cs" /> <Compile Include="Models\LeafInputPhotosynthetic.cs" />
<Compile Include="Models\LeafInputSite.cs" /> <Compile Include="Models\LeafInputSite.cs" />
<Compile Include="Charter\XYPoint.cs" />
<Compile Include="Utility\BoolTypeConverter.cs" />
<Compile Include="Parsers\CntrlComparisonParser.cs" />
<Compile Include="Parsers\CsvParserBase.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Services\ParseInfoAttribute.cs" /> <Compile Include="Utility\ParseInfoAttribute.cs" />
<Compile Include="Services\LeafInputCsvParser.cs" /> <Compile Include="Parsers\LeafInputCsvParser.cs" />
<Compile Include="Services\ParsedObjectFactory.cs" /> <Compile Include="Utility\ParsedObjectFactory.cs" />
<Compile Include="Services\ParseException.cs" /> <Compile Include="Utility\ParseException.cs" />
<Compile Include="Utility\StringExtensions.cs" /> <Compile Include="Utility\StringExtensions.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
+7 -41
View File
@@ -1,49 +1,15 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.ComponentModel.DataAnnotations;
namespace LeafWeb.Core.Models namespace LeafWeb.Core.Models
{ {
[Serializable] /// <summary>
/// The file 'cntrlcomparison.csv', which is in comma-separated-value format, contains outputs from PISCAL that
/// facilitates examination of how well the fitting is.
/// </summary>
public class CntrlComparison public class CntrlComparison
{ {
// Each element will be a PiscalCurve element that contains public virtual IEnumerable<CntrlComparisonFittingInfo> FittingInfo { get; set; }
// all of the output data for one curve. public virtual IEnumerable<CntrlComparisonPhotosyntheticInfo> PhotosyntheticInfo { get; set; }
private readonly List<CurveData> _curveData;
public CntrlComparison()
{
_curveData = new List<CurveData>();
}
public bool ReadFromStream(StreamReader sr, ref String errorMsg)
{
// Skip the first two lines.
sr.ReadLine();
sr.ReadLine();
var lineNbr = 2;
// Now, there should be one or more rows, delimited by a row that has
// CO2i in the first field. Read in all of these rows. The first field
// in each row is the curve ID (input filename).
var more = true;
while (more)
{
var curve = new CurveData(sr, ref errorMsg, ref lineNbr);
if (errorMsg.Length > 0)
return false;
_curveData.Add(curve);
if (sr.EndOfStream)
more = false;
}
return true;
}
public List<CurveData> GetCurveData()
{
return _curveData;
}
} }
} }
+118
View File
@@ -0,0 +1,118 @@
using LeafWeb.Core.Parsers;
using LeafWeb.Core.Utility;
namespace LeafWeb.Core.Models
{
/// <summary>
/// First model prediction is calculated at each sampling point.
/// Then model prediction is calculated at many selected levels of intercelluar CO2 partial pressure
/// levels under three limitation states to enable plotting curves.The same structure is then repeated for
/// each fitting of the same curve with different parameters to be estimated and with different curves. Note
/// that some common information about a curve is repeated for each data point to make the structure of the
/// file as regular as possible.
/// </summary>
public class CntrlComparisonFittingInfo
{
/// <summary>
/// the curve identifier, repeated for each point
/// </summary>
[ParseInfo(1)]
public string CurveID { get; set; }
/// <summary>
/// whether or not chlorophyll fluorescence data are used for identifying the limitation states
/// 0 = not used, 1 = used. (Currently this choice is still under evaluation and therefore ChlFlUse? = 0).
/// </summary>
[ParseInfo(2, alternateTitle: "ChlFlUse?")]
public bool ChlFlUse {get; set; }
/// <summary>
/// whether or not the internal conductance (gi) is fitted for.
/// 0 = not fitted and gi is either infinite or fixed at the value provided by the user.
/// 1 = gi is estiamted, repeated for each point
/// </summary>
[ParseInfo(3, alternateTitle: "FitGi?")]
public bool FitGi {get; set;}
/// <summary>
/// whether or not the chloroplastic CO2 partial pressure photocompensation point is
/// fitted for. 0= not fitted, a prescribed value is used, repeated for each point
/// </summary>
[ParseInfo(4, alternateTitle: "FitGamma*?")]
public bool FitGammaStar {get; set; }
/// <summary>
/// whether or not the apparent Michaelis - Menten constant Kco = Kc(1+O/Ko) is fitted for.
/// 0= not fitted, a prescribed value is calculated from Kc, Ko and the oxygen partial pressure.
/// 1= Fitted for, repeated for each point
/// </summary>
[ParseInfo(5, alternateTitle: "FitKco?")]
public bool FitKco {get; set; }
/// <summary>
/// whether the dark respiration is fitted for. 0= not fitted for, a prescribed value is used.
/// 1= fitted for. repeated for each point
/// </summary>
[ParseInfo(6, alternateTitle: "FitRd?")]
public bool FitRd {get; set;}
/// <summary>
/// whether alpha (the non-returned fraction of the glycolate carbon
/// recycled in the photorespiratory cycle) is fitted for.
/// 0= not fitted for and alpha = 0
/// 1= fitted for, repeated for each point
/// </summary>
[ParseInfo(7, alternateTitle: "FitAlpha?")]
public bool FitAlpha {get; set;}
/// <summary>
/// the combination of limitation states present in the A/Ci dataset. Parameters
/// are estimated for those limitation states that occur in the measured curve, repeated for each point
/// Rubisco: Rubisco limitation(Vcmax, Kco)
/// RuBP: RuBP regeneration limitation(J)
/// Tpu: export limitation(TPU, alpha)
/// </summary>
[ParseInfo(8)]
public string LimitCombina { get; set; }
/// <summary>
/// intercellular CO2 partial pressure
/// </summary>
[ParseInfo(9, units:"Pa")]
public double PCO2i { get; set; }
/// <summary>
/// chloroplastic CO2 partial pressure corresponding to the PCO2i of a point.
/// PCO2c=PCO2i-AnetCal/internal conductance
/// </summary>
[ParseInfo(10, units:"Pa")]
public double PCO2c { get; set; }
/// <summary>
/// measured net assimilation rate
/// </summary>
[ParseInfo(11, units: "umol/m2/s")]
public double AnetMeas { get; set; }
/// <summary>
/// calculated net assimilation rate
/// </summary>
[ParseInfo(12, units: "umol/m2/s")]
public double AnetCal { get; set; }
// TODO: readme has weitedrms, data file has PCOiCal
// weitedrms - (umol/m2/s), root mean square error of the fitting (weiting coefficient =1)
[ParseInfo(13)]
public double PCOiCal { get; set; }
/// <summary>
/// 1 = point limited by rubisco
/// 2 = point limited by RuBP regeneration
/// 3 = point limited by TPU
/// </summary>
[ParseInfo(14, units:"1,2,3")]
public int PointLimitType { get; set; }
public virtual CntrlComparison CntrlComparison { get; set; }
}
}
@@ -0,0 +1,56 @@
using LeafWeb.Core.Parsers;
using LeafWeb.Core.Utility;
namespace LeafWeb.Core.Models
{
/// <summary>
/// The second section gives photosynthesis for each of the three limitation states at selected values of intercellular
/// partial pressure.Note that the corresponding values of chloraplastic CO2 partial pressure depend on the limitation state.
/// </summary>
public class CntrlComparisonPhotosyntheticInfo
{
/// <summary>
/// intercellular CO2 partial pressure
/// </summary>
[ParseInfo(1, units:"Pa")]
public double CO2i { get; set; }
/// <summary>
/// Chloraplastic CO2 partial pressure for Rubisco limited photosynthesis
/// </summary>
[ParseInfo(2, units: "Pa")]
public double CO2cc { get; set; }
/// <summary>
/// Rubisco-limited net assimilation rate calculated with the optimized parameters
/// </summary>
[ParseInfo(3, units: "umol/m2/s")]
public double Ac { get; set; }
/// <summary>
/// Chloraplastic CO2 partial pressure for RuBP regeneration limited photosynthesis
/// </summary>
[ParseInfo(4, units:"Pa")]
public double CO2cj { get; set; }
/// <summary>
/// RuBP regeneration-limited net assimilation rate calculated with estimated parameters
/// </summary>
[ParseInfo(5, units: "umol/m2/s")]
public double Aj { get; set; }
/// <summary>
/// Chloraplastic CO2 partial pressure for export limited photosynthesis
/// </summary>
[ParseInfo(6, units: "Pa")]
public double CO2ct { get; set; }
/// <summary>
/// TPU-limited net assimilation rate calculated with estimated parameters
/// </summary>
[ParseInfo(7, units: "umol/m2/s")]
public double At { get; set; }
public virtual CntrlComparison CntrlComparison { get; set; }
}
}
-59
View File
@@ -1,59 +0,0 @@
using System;
using System.IO;
namespace LeafWeb.Core.Models
{
[Serializable]
public class CurveData
{
private readonly string _curveId;
private readonly CurveParamSet _paramSet1;
private readonly CurveParamSet _paramSet2;
private readonly CurveParamSet _paramSet3;
private readonly CurveParamSet _paramSet4;
public CurveData(StreamReader sr, ref string errMsg, ref int lineNbr)
{
// For each curve in the output file there are four sets of data.
_paramSet1 = new CurveParamSet(sr, ref errMsg, ref lineNbr, ref _curveId);
if (errMsg.Length > 0)
return;
_paramSet2 = new CurveParamSet(sr, ref errMsg, ref lineNbr, ref _curveId);
if (errMsg.Length > 0)
return;
_paramSet3 = new CurveParamSet(sr, ref errMsg, ref lineNbr, ref _curveId);
if (errMsg.Length > 0)
return;
_paramSet4 = new CurveParamSet(sr, ref errMsg, ref lineNbr, ref _curveId);
}
public string GetCurveId()
{
return _curveId;
}
public CurveParamSet CndctFixedCmpPntFixedParams()
{
return _paramSet1;
}
public CurveParamSet CndctFixedCmpPntEstimatedParams()
{
return _paramSet2;
}
public CurveParamSet CndctEstimatedCmpPntFixedParams()
{
return _paramSet3;
}
public CurveParamSet CndctEstimatedCmpPntEstimatedParams()
{
return _paramSet4;
}
}
}
-238
View File
@@ -1,238 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace LeafWeb.Core.Models
{
[Serializable]
public class CurveParamSet
{
private readonly List<XyPoint> _anetMeasChloro1Data; // y=AnetMeas column, x=PCO2c, for PointLimitType=1
private readonly List<XyPoint> _anetMeasChloro2Data; // y=AnetMeas column, x=PCO2c, for PointLimitType=2
private readonly List<XyPoint> _anetMeasChloro3Data; // y=AnetMeas column, x=PCO2c, for PointLimitType=3
private readonly List<XyPoint> _anetMeasInter1Data; // y=AnetMeas column, x=PCO2i, for PointLimitType=1
private readonly List<XyPoint> _anetMeasInter2Data; // y=AnetMeas column, x=PCO2i, for PointLimitType=2
private readonly List<XyPoint> _anetMeasInter3Data; // y=AnetMeas column, x=PCO2i, for PointLimitType=3
private readonly List<XyPoint> _acChloroData; // y=Ac column, x=CO2cc column
private readonly List<XyPoint> _ajChloroData; // y=Aj column, x=CO2cj column
private readonly List<XyPoint> _atChloroData; // y=At column, x=CO2ct column
private readonly List<XyPoint> _acInterData; // y=Ac column, x=CO2i column
private readonly List<XyPoint> _ajInterData; // y=Aj column, x=CO2i column
private readonly List<XyPoint> _atInterData; // y=At column, x=CO2i column
public CurveParamSet()
{
}
public CurveParamSet(StreamReader sr, ref String errMsg, ref int lineNbr, ref String curveId)
{
bool curveIdSet = false, doneWithAnet = false;
String line;
var errorMsg = new StringBuilder("");
List<string> phrases;
XyPoint xyPoint1;
_anetMeasChloro1Data = new List<XyPoint>();
_anetMeasChloro2Data = new List<XyPoint>();
_anetMeasChloro3Data = new List<XyPoint>();
_anetMeasInter1Data = new List<XyPoint>();
_anetMeasInter2Data = new List<XyPoint>();
_anetMeasInter3Data = new List<XyPoint>();
_acChloroData = new List<XyPoint>();
_ajChloroData = new List<XyPoint>();
_atChloroData = new List<XyPoint>();
_acInterData = new List<XyPoint>();
_ajInterData = new List<XyPoint>();
_atInterData = new List<XyPoint>();
while (!doneWithAnet)
{
lineNbr++;
line = sr.ReadLine();
if (line == null)
{
errorMsg.Append("Unexpected end-of-file at line " + lineNbr);
sr.Close();
errMsg = errorMsg.ToString();
return;
}
phrases = SplitCsvLine(line);
String firstField = phrases[0];
if (firstField.Equals("CO2i"))
{
doneWithAnet = true;
}
else
{
// The fields on the line:
// Column Name
// 0 CurveID
// 1 ChlFlUse
// 2 FitGi
// 3 FitGamma
// 4 FitKco
// 5 FitRd
// 6 FitAlpha
// 7 LimitCombina
// 8 PCO2i
// 9 PCO2c
// 10 AnetMeas
// 11 AnetCal
// 12 weitedrms
// 13 PointLimitType
if (!curveIdSet)
{
curveId = firstField;
curveIdSet = true;
}
xyPoint1 = new XyPoint(phrases[9], phrases[10]); // AnetMeas(y), PCO2c(x)
var xyPoint2 = new XyPoint(phrases[8], phrases[10]);
var pointLimitType = Int32.Parse(phrases[13]);
switch (pointLimitType)
{
case 1:
_anetMeasChloro1Data.Add(xyPoint1);
_anetMeasInter1Data.Add(xyPoint2);
break;
case 2:
_anetMeasChloro2Data.Add(xyPoint1);
_anetMeasInter2Data.Add(xyPoint2);
break;
case 3:
_anetMeasChloro3Data.Add(xyPoint1);
_anetMeasInter3Data.Add(xyPoint2);
break;
}
}
}
// The next set of lines will have three pairs of x,y-coordinates to save.
// A blank line signals the end of the data.
var moreData = true;
while (moreData)
{
// The fields on the line:
// Column Name
// 0 CO2i
// 1 CO2cc
// 2 Ac
// 3 CO2cj
// 4 Aj
// 5 CO2ct
// 6 At
lineNbr++;
line = sr.ReadLine();
if (line == null)
{
errorMsg.Append("Unexpected end-of-file at line " + lineNbr);
sr.Close();
errMsg = errorMsg.ToString();
return;
}
if (line.Length == 0)
moreData = false;
else
{
phrases = SplitCsvLine(line);
xyPoint1 = new XyPoint(phrases[1],phrases[2]); // Ac(y),CO2cc(x)
if (xyPoint1.YIsInRange(-20.0, 50.0))
_acChloroData.Add(xyPoint1);
xyPoint1 = new XyPoint(phrases[3], phrases[4]); // Aj(y),CO2cj(x)
if (xyPoint1.YIsInRange(-20.0, 50.0))
_ajChloroData.Add(xyPoint1);
xyPoint1 = new XyPoint(phrases[5], phrases[6]); // At(y),CO2ct(x)
if (xyPoint1.YIsInRange(-20.0, 50.0))
_atChloroData.Add(xyPoint1);
xyPoint1 = new XyPoint(phrases[0], phrases[2]); // Ac(y),CO2i(x)
if (xyPoint1.YIsInRange(-20.0, 50.0))
_acInterData.Add(xyPoint1);
xyPoint1 = new XyPoint(phrases[0], phrases[4]); // Aj(y),CO2i(x)
if (xyPoint1.YIsInRange(-20.0, 50.0))
_ajInterData.Add(xyPoint1);
xyPoint1 = new XyPoint(phrases[0], phrases[6]); // At(y),CO2i(x)
if (xyPoint1.YIsInRange(-20.0, 50.0))
_atInterData.Add(xyPoint1);
}
}
}
/// <summary>
/// This method assumes that the argument is a comma-, blank-, or
/// tab-separated set of strings. It returns an ArrayList of those
/// quantities. Consecutive commas will be returned as an empty string,
/// but all empty strings at the end of the line will be thrown away.
/// </summary>
/// <param name="line"></param>
/// <returns></returns>
private static List<string> SplitCsvLine(String line)
{
int i;
var separator = new [] {',', ' ', '\t'};
var phrases = line.Split(separator);
//int lastNonBlank = -1;
var retPhrases = new List<string>();
for (i = 0; i < phrases.Length; i++)
{
var phrase = phrases[i].Trim();
if (phrase.Length > 0)
// lastNonBlank = i;
retPhrases.Add(phrase);
}
return retPhrases;
}
public List<List<XyPoint>> GetAnetMeasData()
{
var list = new List<List<XyPoint>>
{
_anetMeasChloro1Data,
_anetMeasChloro2Data,
_anetMeasChloro3Data,
_anetMeasInter1Data,
_anetMeasInter2Data,
_anetMeasInter3Data
};
return list;
}
public List<XyPoint> GetAcChloroData()
{
return _acChloroData;
}
public List<XyPoint> GetAjChloroData()
{
return _ajChloroData;
}
public List<XyPoint> GetAtChloroData()
{
return _atChloroData;
}
public List<XyPoint> GetAcInterData()
{
return _acInterData;
}
public List<XyPoint> GetAjInterData()
{
return _ajInterData;
}
public List<XyPoint> GetAtInterData()
{
return _atInterData;
}
}
}
+2 -1
View File
@@ -1,6 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using LeafWeb.Core.Services; using LeafWeb.Core.Parsers;
using LeafWeb.Core.Utility;
namespace LeafWeb.Core.Models namespace LeafWeb.Core.Models
{ {
+2 -1
View File
@@ -1,5 +1,6 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using LeafWeb.Core.Services; using LeafWeb.Core.Parsers;
using LeafWeb.Core.Utility;
namespace LeafWeb.Core.Models namespace LeafWeb.Core.Models
{ {
+2 -1
View File
@@ -1,4 +1,5 @@
using LeafWeb.Core.Services; using LeafWeb.Core.Parsers;
using LeafWeb.Core.Utility;
namespace LeafWeb.Core.Models namespace LeafWeb.Core.Models
{ {
+2 -1
View File
@@ -1,4 +1,5 @@
using LeafWeb.Core.Services; using LeafWeb.Core.Parsers;
using LeafWeb.Core.Utility;
namespace LeafWeb.Core.Models namespace LeafWeb.Core.Models
{ {
+79
View File
@@ -0,0 +1,79 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using LeafWeb.Core.Models;
using LeafWeb.Core.Utility;
namespace LeafWeb.Core.Parsers
{
public class CntrlComparisonParser : CsvParserBase
{
public CntrlComparisonParser(FileSystemInfo csvFile) : base(csvFile)
{
}
public CntrlComparison[] Parse()
{
var fittingTitles = GetNextCsvRowValues();
if (fittingTitles == null)
throw new ParseException($"Could not read data header row on line number {CsvReader.Row}");
var fitUnits = GetNextCsvRowValues();
if (fitUnits == null)
throw new ParseException($"Could not read data units row on line number {CsvReader.Row}");
return ParseCntrlComparisonSet(fittingTitles).ToArray();
}
private IEnumerable<CntrlComparison> ParseCntrlComparisonSet(string[] fittingTitles)
{
var endOfFile = false;
while (!endOfFile)
{
// First Section
var fittingValues = new List<string[]>();
string[] photosyntheticTitles;
while (true)
{
var values = GetNextCsvRowValues();
if (CsvReader.IsRecordEmpty())
throw new ParseException($"Encountered empty line while readding fitting info on line {CsvReader.Row}");
if (values == null) // end of file
yield break;
if (ParsedObjectFactory<CntrlComparisonPhotosyntheticInfo>.IsPropertiesTitlesMatch(values))
{
photosyntheticTitles = values;
break;
}
fittingValues.Add(values);
}
var photosyntheticValues = new List<string[]>();
while (true)
{
var values = GetNextCsvRowValues();
if (CsvReader.IsRecordEmpty()) // end of set
break;
if (values == null)
{
endOfFile = true;
break;
}
photosyntheticValues.Add(values);
}
var fittingInfo =
ParsedObjectFactory<CntrlComparisonFittingInfo>
.Create(fittingTitles, fittingValues.ToArray());
var photosyntheticInfo =
ParsedObjectFactory<CntrlComparisonPhotosyntheticInfo>
.Create(photosyntheticTitles, photosyntheticValues.ToArray());
yield return new CntrlComparison
{
FittingInfo = fittingInfo,
PhotosyntheticInfo = photosyntheticInfo
};
}
}
}
}
+49
View File
@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.IO;
using CsvHelper;
using CsvHelper.Configuration;
namespace LeafWeb.Core.Parsers
{
public class CsvParserBase : IDisposable
{
protected readonly FileSystemInfo CsvFile;
private readonly StreamReader _reader;
protected readonly CsvReader CsvReader;
protected CsvParserBase(FileSystemInfo csvFile)
{
CsvFile = csvFile;
if (!csvFile.Exists)
throw new FileNotFoundException($"Cannot find file '{csvFile.Name}'");
_reader = File.OpenText(csvFile.FullName);
var csvConfiguration = new CsvConfiguration { HasHeaderRecord = false, IgnoreBlankLines = false};
CsvReader = new CsvReader(_reader, csvConfiguration);
}
protected string[] GetNextCsvRowValues()
{
// get values from row
if (!CsvReader.Read())
return null;
// put all the values from this row into an array
var values = new List<string>();
var index = 0;
string value;
while (CsvReader.TryGetField(index, out value))
{
values.Add(value);
index++;
}
return values.ToArray();
}
public void Dispose()
{
_reader.Dispose();
}
}
}
@@ -2,33 +2,22 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using CsvHelper; using CsvHelper;
using CsvHelper.Configuration;
using LeafWeb.Core.Models; using LeafWeb.Core.Models;
using LeafWeb.Core.Utility;
namespace LeafWeb.Core.Services namespace LeafWeb.Core.Parsers
{ {
public class LeafInputCsvParser : IDisposable public class LeafInputCsvParser : CsvParserBase
{ {
private readonly FileSystemInfo _csvFile; public LeafInputCsvParser(FileSystemInfo csvFile) : base(csvFile)
private readonly StreamReader _reader;
private readonly CsvReader _csv;
public LeafInputCsvParser(FileSystemInfo csvFile)
{ {
_csvFile = csvFile;
if (!csvFile.Exists)
throw new FileNotFoundException("Cannot find file '" + csvFile.Name + "'");
_reader = File.OpenText(csvFile.FullName);
var csvConfiguration = new CsvConfiguration {HasHeaderRecord = false};
_csv = new CsvReader(_reader, csvConfiguration);
} }
public LeafInput Parse() public LeafInput Parse()
{ {
// First 10 lines // First 10 lines
var leafInput = ParseLeafInput(); var leafInput = ParseLeafInput();
leafInput.FileName = _csvFile.Name; leafInput.FileName = CsvFile.Name;
// Next 3 (Header, Units, and Values) // Next 3 (Header, Units, and Values)
leafInput.Site = ParseLeafInputSite(); leafInput.Site = ParseLeafInputSite();
@@ -47,46 +36,28 @@ namespace LeafWeb.Core.Services
var items = new List<string>(); var items = new List<string>();
for (var i = 0; i < 10; i++) for (var i = 0; i < 10; i++)
{ {
if (!_csv.Read()) if (!CsvReader.Read())
throw new ParseException("Could not read line number " + _csv.Row); throw new ParseException("Could not read line number " + CsvReader.Row);
string field; string field;
if (!_csv.TryGetField(0, out field)) if (!CsvReader.TryGetField(0, out field))
throw new ParseException("Could not read first field on line number " + _csv.Row); throw new ParseException("Could not read first field on line number " + CsvReader.Row);
items.Add(field); items.Add(field);
} }
return ParsedObjectFactory<LeafInput>.Create(items.ToArray()); return ParsedObjectFactory<LeafInput>.Create(items.ToArray());
} }
private string[] GetNextCsvRowValues()
{
// get values from row
if (!_csv.Read())
return null;
// put all the values from this row into an array
var values = new List<string>();
var index = 0;
string value;
while (_csv.TryGetField(index, out value))
{
values.Add(value);
index++;
}
return values.ToArray();
}
private LeafInputSite ParseLeafInputSite() private LeafInputSite ParseLeafInputSite()
{ {
var titles = GetNextCsvRowValues(); var titles = GetNextCsvRowValues();
if (titles == null) if (titles == null)
throw new ParseException("Could not read site header row on line number " + _csv.Row); throw new ParseException("Could not read site header row on line number " + CsvReader.Row);
var units = GetNextCsvRowValues(); var units = GetNextCsvRowValues();
if (units == null) if (units == null)
throw new ParseException("Could not read site units row on line number " + _csv.Row); throw new ParseException("Could not read site units row on line number " + CsvReader.Row);
var values = GetNextCsvRowValues(); var values = GetNextCsvRowValues();
if (values == null) if (values == null)
throw new ParseException("Could not read site value row on line number " + _csv.Row); throw new ParseException("Could not read site value row on line number " + CsvReader.Row);
var items = new List<Tuple<string, string>>(); var items = new List<Tuple<string, string>>();
for (var i = 0; i < titles.Length && i < values.Length; i++) for (var i = 0; i < titles.Length && i < values.Length; i++)
@@ -101,13 +72,13 @@ namespace LeafWeb.Core.Services
{ {
var titles = GetNextCsvRowValues(); var titles = GetNextCsvRowValues();
if (titles == null) if (titles == null)
throw new ParseException("Could not read photosynthetic header row on line number " + _csv.Row); throw new ParseException("Could not read photosynthetic header row on line number " + CsvReader.Row);
var units = GetNextCsvRowValues(); var units = GetNextCsvRowValues();
if (units == null) if (units == null)
throw new ParseException("Could not read photosynthetic units row on line number " + _csv.Row); throw new ParseException("Could not read photosynthetic units row on line number " + CsvReader.Row);
var values = GetNextCsvRowValues(); var values = GetNextCsvRowValues();
if (values == null) if (values == null)
throw new ParseException("Could not read photosynthetic value row on line number " + _csv.Row); throw new ParseException("Could not read photosynthetic value row on line number " + CsvReader.Row);
var items = new List<Tuple<string, string>>(); var items = new List<Tuple<string, string>>();
for (var i = 0; i < titles.Length && i < values.Length; i++) for (var i = 0; i < titles.Length && i < values.Length; i++)
@@ -122,10 +93,10 @@ namespace LeafWeb.Core.Services
{ {
var titles = GetNextCsvRowValues(); var titles = GetNextCsvRowValues();
if (titles == null) if (titles == null)
throw new ParseException("Could not read data header row on line number " + _csv.Row); throw new ParseException("Could not read data header row on line number " + CsvReader.Row);
var units = GetNextCsvRowValues(); var units = GetNextCsvRowValues();
if (units == null) if (units == null)
throw new ParseException("Could not read data units row on line number " + _csv.Row); throw new ParseException("Could not read data units row on line number " + CsvReader.Row);
var valueArrays = new List<string[]>(); var valueArrays = new List<string[]>();
while (true) while (true)
@@ -138,11 +109,6 @@ namespace LeafWeb.Core.Services
return ParsedObjectFactory<LeafInputData>.Create(titles, valueArrays.ToArray()); return ParsedObjectFactory<LeafInputData>.Create(titles, valueArrays.ToArray());
} }
public void Dispose()
{
_reader.Dispose();
}
public static void ExportCsv(string filename, IEnumerable<LeafInput> leafInputs) public static void ExportCsv(string filename, IEnumerable<LeafInput> leafInputs)
{ {
using (var textWriter = new StreamWriter(filename)) using (var textWriter = new StreamWriter(filename))
+47
View File
@@ -0,0 +1,47 @@
using System;
using System.ComponentModel;
using System.Globalization;
namespace LeafWeb.Core.Utility
{
// http://stackoverflow.com/a/19022931/99492
public class BoolTypeConverter : TypeConverter
{
public static void Register()
{
TypeDescriptor.AddAttributes(typeof(Boolean),
new TypeConverterAttribute(typeof(BoolTypeConverter)));
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(bool))
{
return true;
}
return base.CanConvertTo(context, destinationType);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (value is string)
{
var s = value as string;
if (string.IsNullOrEmpty(s))
return false;
switch (s.Trim().ToUpper())
{
case "TRUE":
case "YES":
case "1":
case "-1":
return true;
default:
return false;
}
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
}
@@ -1,6 +1,6 @@
using System; using System;
namespace LeafWeb.Core.Services namespace LeafWeb.Core.Utility
{ {
public class ParseException : Exception public class ParseException : Exception
{ {
@@ -1,9 +1,8 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using LeafWeb.Core.Utility;
namespace LeafWeb.Core.Services namespace LeafWeb.Core.Utility
{ {
[AttributeUsage(AttributeTargets.Property)] [AttributeUsage(AttributeTargets.Property)]
public class ParseInfoAttribute : Attribute public class ParseInfoAttribute : Attribute
@@ -1,12 +1,19 @@
using System; using System;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using Fasterflect; using Fasterflect;
namespace LeafWeb.Core.Services namespace LeafWeb.Core.Utility
{ {
public static class ParsedObjectFactory<T> where T : new() public static class ParsedObjectFactory<T> where T : new()
{ {
static ParsedObjectFactory()
{
// register this for usage by TypeDescriptor.GetConverter
BoolTypeConverter.Register();
}
private static PropertyInfo[] GetProperties() private static PropertyInfo[] GetProperties()
{ {
var propertyInfos = typeof(T).Properties(); var propertyInfos = typeof(T).Properties();
@@ -52,7 +59,7 @@ namespace LeafWeb.Core.Services
{ {
object convertedVal; object convertedVal;
if (!TryConvertValue(property, value, out convertedVal)) if (!TryConvertValue(property, value, out convertedVal))
throw new ParseException(string.Format("Cannot convert value '{0}' for {1} at line number {2}", value, property.Name, lineNumber)); throw new ParseException($"Cannot convert value '{value}' for {property.Name} at line number {lineNumber}");
property.Set(obj, convertedVal); property.Set(obj, convertedVal);
} }
} }
@@ -83,7 +90,7 @@ namespace LeafWeb.Core.Services
{ {
object convertedVal; object convertedVal;
if (!TryConvertValue(property, value, out convertedVal)) if (!TryConvertValue(property, value, out convertedVal))
throw new ParseException(string.Format("Cannot convert value '{0}' for {1} in position {2}", value, property.Name, position)); throw new ParseException($"Cannot convert value '{value}' for {property.Name} in position {position}");
property.Set(obj, convertedVal); property.Set(obj, convertedVal);
} }
} }
@@ -113,7 +120,7 @@ namespace LeafWeb.Core.Services
{ {
object convertedVal; object convertedVal;
if (!TryConvertValue(property, value, out convertedVal)) if (!TryConvertValue(property, value, out convertedVal))
throw new ParseException(string.Format("Cannot convert value '{0}' for {1} in position {2}", value, property.Name, position)); throw new ParseException($"Cannot convert value '{value}' for {property.Name} in position {position}");
property.Set(obj, convertedVal); property.Set(obj, convertedVal);
} }
} }
@@ -127,26 +134,55 @@ namespace LeafWeb.Core.Services
private static PropertyInfo MatchProperty(PropertyInfo[] properties, string title, int position) private static PropertyInfo MatchProperty(PropertyInfo[] properties, string title, int position)
{ {
var property = return
properties properties.FirstOrDefault(p => p.Attribute<ParseInfoAttribute>().IsTitleMatch(title)) ??
.FirstOrDefault(p => p.Attribute<ParseInfoAttribute>().IsTitleMatch(title)); properties.FirstOrDefault(p => p.Attribute<ParseInfoAttribute>().IsPositionMatch(position));
}
if (property == null) private static PropertyInfo MatchPropertyExact(PropertyInfo[] properties, string title, int position)
{
return
properties
.FirstOrDefault(p =>
{
var attribute = p.Attribute<ParseInfoAttribute>();
return attribute.IsTitleMatch(title) && attribute.IsPositionMatch(position);
});
}
public static bool IsPropertiesTitlesMatch(string[] titles)
{
var properties = GetProperties();
var propertyMatch = 0;
var propertyNoMatch = 0;
for (var i = 0; i < titles.Length; i++)
{ {
property = var title = titles[i];
properties var position = i + 1;
.FirstOrDefault(p => p.Attribute<ParseInfoAttribute>().IsPositionMatch(position)); if (string.IsNullOrEmpty(title))
continue;
var property = MatchPropertyExact(properties, title, position);
if (property != null)
propertyMatch++;
else
propertyNoMatch++;
} }
return property;
return propertyMatch / (double) propertyNoMatch > .9;
} }
private static bool TryConvertValue(PropertyInfo property, object value, out object convertedValue) private static bool TryConvertValue(PropertyInfo property, object value, out object convertedValue)
{ {
try try
{ {
// http://stackoverflow.com/questions/3531318/convert-changetype-fails-on-nullable-types // http://stackoverflow.com/questions/3531318/convert-changetype-fails-on-nullable-types
var t = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType; var t = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
convertedValue = Convert.ChangeType(value, t); // convertedValue = Convert.ChangeType(value, t);
var converter = TypeDescriptor.GetConverter(t);
convertedValue = converter.ConvertTo(value, t);
} }
catch (Exception) catch (Exception)
{ {
+3 -4
View File
@@ -1,5 +1,4 @@
using System; using System.Globalization;
using System.Globalization;
using System.Linq; using System.Linq;
namespace LeafWeb.Core.Utility namespace LeafWeb.Core.Utility
@@ -9,9 +8,9 @@ namespace LeafWeb.Core.Utility
public static string SplitCamelCase(this string str) public static string SplitCamelCase(this string str)
{ {
return str.Aggregate( return str.Aggregate(
String.Empty, string.Empty,
(current, c) => (current, c) =>
current + (Char.IsUpper(c) && current.Length > 0 ? " " + c : c.ToString(CultureInfo.InvariantCulture))); current + (char.IsUpper(c) && current.Length > 0 ? " " + c : c.ToString(CultureInfo.InvariantCulture)));
} }
} }
} }
+27 -29
View File
@@ -6,23 +6,24 @@ using System.IO;
using System.Web.UI; using System.Web.UI;
using System.Web.UI.DataVisualization.Charting; using System.Web.UI.DataVisualization.Charting;
using System.Web.UI.WebControls; using System.Web.UI.WebControls;
using LeafWeb.Core.Charter;
using LeafWeb.Core.Models; using LeafWeb.Core.Models;
namespace LeafWeb.Web.Charter namespace LeafWeb.Web.Charter
{ {
public partial class LeafWebCharter : UserControl public partial class LeafWebCharter : UserControl
{ {
protected void ReadFile(StreamReader sr, ref String errMsg) protected void ReadFile(StreamReader sr, ref string errMsg)
{ {
var pisOut = new CntrlComparison(); var pisOut = new CurveDataList();
if (!pisOut.ReadFromStream(sr, ref errMsg)) if (!pisOut.ReadFromStream(sr))
{ {
ErrorLBL.Text = errMsg; ErrorLBL.Text = errMsg;
ErrorLBL.Visible = true; ErrorLBL.Visible = true;
return; return;
} }
Session["LeafChartData"] = pisOut; Session["LeafChartData"] = pisOut;
var aCopy = (CntrlComparison) Session["LeafChartData"]; var aCopy = (CurveDataList) Session["LeafChartData"];
// The data was successfully read from the file. We must now // The data was successfully read from the file. We must now
// display the curveIDs from the file and prompt the user to pick // display the curveIDs from the file and prompt the user to pick
@@ -31,12 +32,12 @@ namespace LeafWeb.Web.Charter
var curveDT = new DataTable(); var curveDT = new DataTable();
curveDT.Columns.Add(new DataColumn("curveID")); curveDT.Columns.Add(new DataColumn("curveID"));
var curveData = pisOut.GetCurveData(); var curveData = pisOut.CurveData;
for (var i = 0; i < curveData.Count; i++) for (var i = 0; i < curveData.Count; i++)
{ {
var aCurve = curveData[i]; var aCurve = curveData[i];
var dr = curveDT.NewRow(); var dr = curveDT.NewRow();
dr["curveID"] = aCurve.GetCurveId(); dr["curveID"] = aCurve.CurveId;
curveDT.Rows.Add(dr); curveDT.Rows.Add(dr);
} }
@@ -48,7 +49,7 @@ namespace LeafWeb.Web.Charter
// cntrlcomparison // cntrlcomparison
public void ProduceCharts(CntrlComparison pisOut) public void ProduceCharts(CurveDataList pisOut)
{ {
// If the session has timed out, use the selected index from the GridView // If the session has timed out, use the selected index from the GridView
// to determine which job to chart. // to determine which job to chart.
@@ -62,14 +63,14 @@ namespace LeafWeb.Web.Charter
// break; // break;
// } // }
var curveData = pisOut.GetCurveData(); var curveData = pisOut.CurveData;
var curve = curveData[1]; var curve = curveData[1];
var curveId = curve.GetCurveId(); var curveId = curve.CurveId;
CurveSeries(curveId, curve.CndctFixedCmpPntFixedParams(), ChartChloro1, ChartInter1, "Internal conductance fixed, compensation point and M-M constants fixed"); CurveSeries(curveId, curve.FixedCndFixedCmp, ChartChloro1, ChartInter1, "Internal conductance fixed, compensation point and M-M constants fixed");
CurveSeries(curveId, curve.CndctFixedCmpPntEstimatedParams(), ChartChloro2, ChartInter2, "Internal conductance fixed, compensation point and M-M constants estimated"); CurveSeries(curveId, curve.FixedCndEstimatedCmp, ChartChloro2, ChartInter2, "Internal conductance fixed, compensation point and M-M constants estimated");
CurveSeries(curveId, curve.CndctEstimatedCmpPntFixedParams(), ChartChloro3, ChartInter3, "Internal conductance estimated, compensation point and M-M constants fixed"); CurveSeries(curveId, curve.EstimatedCndFixedCmp, ChartChloro3, ChartInter3, "Internal conductance estimated, compensation point and M-M constants fixed");
CurveSeries(curveId, curve.CndctEstimatedCmpPntEstimatedParams(), ChartChloro4, ChartInter4, "Internal conductance estimated, compensation point and M-M constants estimated"); CurveSeries(curveId, curve.EstimatedCndEstimatedCmp, ChartChloro4, ChartInter4, "Internal conductance estimated, compensation point and M-M constants estimated");
} }
private static Chart GetChart() private static Chart GetChart()
@@ -203,11 +204,9 @@ namespace LeafWeb.Web.Charter
private static void CurveSeries(string curveId, CurveParamSet paramSet, Chart chloroChart, Chart interChart, string chartTitle) private static void CurveSeries(string curveId, CurveParamSet paramSet, Chart chloroChart, Chart interChart, string chartTitle)
{ {
var paramSetAnet = paramSet.GetAnetMeasData(); var anetMeasChloro1 = paramSet.AnetMeasChloro1Data;
var anetMeasChloro2 = paramSet.AnetMeasChloro2Data;
var anetMeasChloro1 = paramSetAnet[0]; var anetMeasChloro3 = paramSet.AnetMeasChloro3Data;
var anetMeasChloro2 = paramSetAnet[1];
var anetMeasChloro3 = paramSetAnet[2];
// Set the points for the symbol series for paramater set 1, chloroplastic // Set the points for the symbol series for paramater set 1, chloroplastic
setAnetMeasPoints(anetMeasChloro1, chloroChart.Series["Rubisco-limited"]); setAnetMeasPoints(anetMeasChloro1, chloroChart.Series["Rubisco-limited"]);
@@ -217,9 +216,9 @@ namespace LeafWeb.Web.Charter
setAnetMeasPoints(anetMeasChloro3, tpuSeries); setAnetMeasPoints(anetMeasChloro3, tpuSeries);
chloroChart.Series.Add(tpuSeries); chloroChart.Series.Add(tpuSeries);
var anetMeasInter1 = paramSetAnet[3]; var anetMeasInter1 = paramSet.AnetMeasInter1Data;
var anetMeasInter2 = paramSetAnet[4]; var anetMeasInter2 = paramSet.AnetMeasInter2Data;
var anetMeasInter3 = paramSetAnet[5]; var anetMeasInter3 = paramSet.AnetMeasInter3Data;
// Set the points for the symbol series for paramater set 1, intercellular // Set the points for the symbol series for paramater set 1, intercellular
setAnetMeasPoints(anetMeasInter1, interChart.Series["Rubisco-limited"]); setAnetMeasPoints(anetMeasInter1, interChart.Series["Rubisco-limited"]);
@@ -229,18 +228,18 @@ namespace LeafWeb.Web.Charter
setAnetMeasPoints(anetMeasInter3, tpuSeries); setAnetMeasPoints(anetMeasInter3, tpuSeries);
interChart.Series.Add(tpuSeries); interChart.Series.Add(tpuSeries);
var acChloroList = paramSet.GetAcChloroData(); var acChloroList = paramSet.AcChloroData;
var ajChloroList = paramSet.GetAjChloroData(); var ajChloroList = paramSet.AjChloroData;
var atChloroList = paramSet.GetAtChloroData(); var atChloroList = paramSet.AtChloroData;
// Set the points on the asymptote curve for parameter set 1, chloroplast // Set the points on the asymptote curve for parameter set 1, chloroplast
setAsymptotePoints(acChloroList, chloroChart.Series["acCurve"]); setAsymptotePoints(acChloroList, chloroChart.Series["acCurve"]);
setAsymptotePoints(ajChloroList, chloroChart.Series["ajCurve"]); setAsymptotePoints(ajChloroList, chloroChart.Series["ajCurve"]);
setAsymptotePoints(atChloroList, chloroChart.Series["atCurve"]); setAsymptotePoints(atChloroList, chloroChart.Series["atCurve"]);
var acInterList = paramSet.GetAcInterData(); var acInterList = paramSet.AcInterData;
var ajInterList = paramSet.GetAjInterData(); var ajInterList = paramSet.AjInterData;
var atInterList = paramSet.GetAtInterData(); var atInterList = paramSet.AtInterData;
// Set the points on the asymptote curve for parameter set 1, intercellular // Set the points on the asymptote curve for parameter set 1, intercellular
setAsymptotePoints(acInterList, interChart.Series["acCurve"]); setAsymptotePoints(acInterList, interChart.Series["acCurve"]);
@@ -251,8 +250,7 @@ namespace LeafWeb.Web.Charter
var titleFont = new Font("Times New Roman", 12, FontStyle.Bold); var titleFont = new Font("Times New Roman", 12, FontStyle.Bold);
var title = new Title("LeafWeb curveID = " + curveId + var title = new Title("LeafWeb curveID = " + curveId +
"\n" + chartTitle); "\n" + chartTitle) {Font = titleFont};
title.Font = titleFont;
chloroChart.Titles.Add(title); chloroChart.Titles.Add(title);
interChart.Titles.Add(title); interChart.Titles.Add(title);
Binary file not shown.
+7 -5
View File
@@ -143,8 +143,6 @@
<ItemGroup> <ItemGroup>
<Compile Include="App_Start\BundleConfig.cs" /> <Compile Include="App_Start\BundleConfig.cs" />
<Compile Include="App_Start\RouteConfig.cs" /> <Compile Include="App_Start\RouteConfig.cs" />
<Compile Include="Charter\CurveData.cs" />
<Compile Include="Charter\CurveParamSet.cs" />
<Compile Include="Charter\LeafWebCharter.ascx.cs"> <Compile Include="Charter\LeafWebCharter.ascx.cs">
<DependentUpon>LeafWebCharter.ascx</DependentUpon> <DependentUpon>LeafWebCharter.ascx</DependentUpon>
<SubType>ASPXCodeBehind</SubType> <SubType>ASPXCodeBehind</SubType>
@@ -152,8 +150,6 @@
<Compile Include="Charter\LeafWebCharter.ascx.designer.cs"> <Compile Include="Charter\LeafWebCharter.ascx.designer.cs">
<DependentUpon>LeafWebCharter.ascx</DependentUpon> <DependentUpon>LeafWebCharter.ascx</DependentUpon>
</Compile> </Compile>
<Compile Include="Charter\PiscalOutput.cs" />
<Compile Include="Charter\XYPoint.cs" />
<Compile Include="Controllers\LeafCharterController.cs" /> <Compile Include="Controllers\LeafCharterController.cs" />
<Compile Include="Controllers\PagesController.cs" /> <Compile Include="Controllers\PagesController.cs" />
<Compile Include="Global.asax.cs"> <Compile Include="Global.asax.cs">
@@ -173,7 +169,7 @@
<Content Include="Views\_ViewStart.cshtml" /> <Content Include="Views\_ViewStart.cshtml" />
<Content Include="Views\Pages\DataRequirements.cshtml" /> <Content Include="Views\Pages\DataRequirements.cshtml" />
<Content Include="Scripts\jquery-1.9.1.min.map" /> <Content Include="Scripts\jquery-1.9.1.min.map" />
<Content Include="Views\LeafCharter\LeafCharter.cshtml" /> <Content Include="Views\LeafCharter\Index.cshtml" />
<None Include="Web.Debug.config"> <None Include="Web.Debug.config">
<DependentUpon>Web.config</DependentUpon> <DependentUpon>Web.config</DependentUpon>
</None> </None>
@@ -185,6 +181,12 @@
<Folder Include="App_Data\" /> <Folder Include="App_Data\" />
<Folder Include="Models\" /> <Folder Include="Models\" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Core\Core.csproj">
<Project>{25baed75-7e75-4d11-90d9-358472054df6}</Project>
<Name>Core</Name>
</ProjectReference>
</ItemGroup>
<PropertyGroup> <PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion> <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>