currycarbon 0.2.1.1 → 0.2.1.2
raw patch · 15 files changed
+187/−184 lines, 15 filesdep ~optparse-applicativePVP ok
version bump matches the API change (PVP)
Dependency ranges changed: optparse-applicative
API changes (from Hackage documentation)
Files
- CHANGELOG.md +1/−0
- README.md +3/−4
- currycarbon.cabal +3/−3
- src-executables/Main-currycarbon.hs +12/−11
- src/Currycarbon.hs +12/−12
- src/Currycarbon/CLI/RunCalibrate.hs +17/−16
- src/Currycarbon/CalCurves/Intcal20.hs +2/−2
- src/Currycarbon/Calibration/Bchron.hs +8/−8
- src/Currycarbon/Calibration/Calibration.hs +21/−20
- src/Currycarbon/Calibration/MatrixMult.hs +10/−10
- src/Currycarbon/Calibration/Utils.hs +11/−11
- src/Currycarbon/Parsers.hs +45/−45
- src/Currycarbon/SumCalibration.hs +15/−15
- src/Currycarbon/Types.hs +23/−23
- src/Currycarbon/Utils.hs +4/−4
CHANGELOG.md view
@@ -1,3 +1,4 @@+- V 0.2.1.2: Maintenance: Switched to a newer compiler/resolver version, lifted some dependency restrictions, ran stylish-haskell on the entire codebase, updated the github actions, deprecated the haddock documentation for the dev version on GitHub - V 0.2.1.1: Lifted some restrictions regarding the upper version bounds of dependencies - V 0.2.1.0: Added a mechanism to detect terminal encoding and fall back on a simpler CLI plot if it is not UTF-8 - V 0.2.0.1: Brought sample names back to default CLI output
README.md view
@@ -8,14 +8,13 @@ ### Library -The Haskell library is available on Hackage [here](https://hackage.haskell.org/package/currycarbon).-This repository stores the dev version with up-to-date documentation available [here](https://nevrome.github.io/currycarbon).+The Haskell library is available on Hackage [here](https://hackage.haskell.org/package/currycarbon) and on Stackage [here](https://www.stackage.org/package/currycarbon). ### CLI app For stable release versions we automatically prepare statically built binaries that can be downloaded and run directly. -You can download them here: [ [Linux 📥](https://github.com/nevrome/currycarbon/releases/latest/download/currycarbon-Linux) | [macOS 📥](https://github.com/nevrome/currycarbon/releases/latest/download/currycarbon-macOS) | [Windows 📥](https://github.com/nevrome/currycarbon/releases/latest/download/currycarbon-Windows.exe) ]. Older release versions are available [here](https://github.com/nevrome/currycarbon/releases).+You can download them here: [ [Linux 📥](https://github.com/nevrome/currycarbon/releases/latest/download/currycarbon-Linux) | [macOS 📥](https://github.com/nevrome/currycarbon/releases/latest/download/currycarbon-macOS) ]. Older release versions (some with Windows builds) are available [here](https://github.com/nevrome/currycarbon/releases). So in Linux you can run the following commands to get started: @@ -113,7 +112,7 @@ ### For developers who want to edit the code -To install the latest development version (!) you can follow these steps:+To install the latest development version you can follow these steps: 1. Install the Haskell build tool [Stack](https://docs.haskellstack.org/en/stable/README/) 2. Clone the repository
currycarbon.cabal view
@@ -1,5 +1,5 @@ name: currycarbon-version: 0.2.1.1+version: 0.2.1.2 synopsis: A package for simple, fast radiocarbon calibration description: Radiocarbon calibration with the intercept method optimised for fast calibration of many dates. homepage: https://github.com/nevrome/currycarbon@@ -49,11 +49,11 @@ build-depends: currycarbon , base- , optparse-applicative >= 0.16 && < 0.18+ , optparse-applicative >= 0.16 && < 0.19 , filepath other-modules: Paths_currycarbon default-language: Haskell2010 ghc-options: - -threaded -with-rtsopts=-N+ -threaded -with-rtsopts=-N -optP-Wno-nonportable-include-path
src-executables/Main-currycarbon.hs view
@@ -1,17 +1,18 @@ {-# LANGUAGE OverloadedStrings #-} -import Currycarbon.CLI.RunCalibrate (runCalibrate, - CalibrateOptions (..))+import Currycarbon.CLI.RunCalibrate (CalibrateOptions (..),+ runCalibrate) import Currycarbon.Parsers import Currycarbon.Types import Currycarbon.Utils-import Paths_currycarbon (version)+import Paths_currycarbon (version) -import Control.Exception (catch)-import Data.Version (showVersion)-import qualified Options.Applicative as OP-import System.Exit (exitFailure)-import System.IO (hPutStrLn, stderr, stdout, hGetEncoding)+import Control.Exception (catch)+import Data.Version (showVersion)+import qualified Options.Applicative as OP+import System.Exit (exitFailure)+import System.IO (hGetEncoding, hPutStrLn, stderr,+ stdout) -- * CLI interface configuration -- -- $cliInterface@@ -120,19 +121,19 @@ optParseAllowOutside :: OP.Parser (Bool) optParseAllowOutside = OP.switch (- OP.long "allowOutside" <> + OP.long "allowOutside" <> OP.help "Allow calibrations to run outside the range of the calibration curve" ) optParseDontInterpolateCalCurve :: OP.Parser (Bool) optParseDontInterpolateCalCurve = OP.switch (- OP.long "noInterpolation" <> + OP.long "noInterpolation" <> OP.help "Don't interpolate the calibration curve" ) optParseQuiet :: OP.Parser (Bool) optParseQuiet = OP.switch (- OP.long "quiet" <> + OP.long "quiet" <> OP.short 'q' <> OP.help "Suppress the printing of calibration results to the command line" )
src/Currycarbon.hs view
@@ -1,10 +1,10 @@--- | This module implements an algorithm for the calibration of +-- | This module implements an algorithm for the calibration of -- [radiocarbon dates](https://en.wikipedia.org/wiki/Radiocarbon_dating). -- This is a standard procedure in Archaeology and other fields working -- with radiocarbon dating. module Currycarbon (- + -- * Calibration -- $calibration calibrateDates,@@ -48,18 +48,18 @@ normalizeCalPDF ) where -import Currycarbon.Calibration.Calibration-import Currycarbon.Parsers-import Currycarbon.SumCalibration-import Currycarbon.Types-import Currycarbon.CalCurves.Intcal20-import Currycarbon.Calibration.Utils (normalizeCalPDF)+import Currycarbon.CalCurves.Intcal20+import Currycarbon.Calibration.Calibration+import Currycarbon.Calibration.Utils (normalizeCalPDF)+import Currycarbon.Parsers+import Currycarbon.SumCalibration+import Currycarbon.Types {- $calibration -The main function in this module 'calibrateDates' calibrates -radiocarbon dates, given the uncalibrated input dates, a calibration -curve and some configuration options. +The main function in this module 'calibrateDates' calibrates+radiocarbon dates, given the uncalibrated input dates, a calibration+curve and some configuration options. * For the input dates there is a dedicated data type 'UncalC14'. These can be read from a .csv file with 'readUncalC14FromFile'.@@ -111,7 +111,7 @@ These can also be written to a file with 'writeCalC14s'. -'renderCalDatesPretty' finally combines 'UncalC14', 'CalPDF' and +'renderCalDatesPretty' finally combines 'UncalC14', 'CalPDF' and 'CalC14' to produce nice command line output summarising the calibration result for a given sample. -}
src/Currycarbon/CLI/RunCalibrate.hs view
@@ -10,24 +10,25 @@ import Currycarbon.Types import Currycarbon.Utils -import Control.Monad (when, unless)-import Data.Maybe (fromJust, isJust, fromMaybe)-import System.IO (hPutStrLn, stderr, stdout)+import Control.Monad (unless, when)+import Data.Maybe (fromJust, fromMaybe,+ isJust)+import System.IO (hPutStrLn, stderr, stdout) -- | A data type to represent the options to the CLI module function runCalibrate data CalibrateOptions = CalibrateOptions {- _calibrateExprs :: [CalExpr] -- ^ String listing the uncalibrated dates that should be calibrated- , _calibrateExprFiles :: [FilePath] -- ^ List of files with uncalibrated dates to be calibrated- , _calibrateCalCurveFile :: Maybe FilePath -- ^ Path to a .14c file- , _calibrateCalibrationMethod :: CalibrationMethod -- ^ Calibration algorithm that should be used- , _calibrateAllowOutside :: Bool -- ^ Allow calibration to run outside of the range of the calibration curve + _calibrateExprs :: [CalExpr] -- ^ String listing the uncalibrated dates that should be calibrated+ , _calibrateExprFiles :: [FilePath] -- ^ List of files with uncalibrated dates to be calibrated+ , _calibrateCalCurveFile :: Maybe FilePath -- ^ Path to a .14c file+ , _calibrateCalibrationMethod :: CalibrationMethod -- ^ Calibration algorithm that should be used+ , _calibrateAllowOutside :: Bool -- ^ Allow calibration to run outside of the range of the calibration curve , _calibrateDontInterpolateCalCurve :: Bool -- ^ Don't interpolate the calibration curve- , _calibrateQuiet :: Bool -- ^ Suppress the printing of calibration results to the command line- , _calibrateStdOutEncoding :: String -- ^ Encoding of the stdout stream (show TextEncoding)- , _calibrateDensityFile :: Maybe FilePath -- ^ Path to an output file (see CLI documentation)- , _calibrateHDRFile :: Maybe FilePath -- ^ Path to an output file- , _calibrateCalCurveSegmentFile :: Maybe FilePath -- ^ Path to an output file - , _calibrateCalCurveMatrixFile :: Maybe FilePath -- ^ Path to an output file + , _calibrateQuiet :: Bool -- ^ Suppress the printing of calibration results to the command line+ , _calibrateStdOutEncoding :: String -- ^ Encoding of the stdout stream (show TextEncoding)+ , _calibrateDensityFile :: Maybe FilePath -- ^ Path to an output file (see CLI documentation)+ , _calibrateHDRFile :: Maybe FilePath -- ^ Path to an output file+ , _calibrateCalCurveSegmentFile :: Maybe FilePath -- ^ Path to an output file+ , _calibrateCalCurveMatrixFile :: Maybe FilePath -- ^ Path to an output file } -- | Interface function to trigger calibration from the command line@@ -99,7 +100,7 @@ printE :: CurrycarbonException -> IO () printE e = hPutStrLn stderr $ renderCurrycarbonException e --- | Helper function to replace empty input names with a sequence of numbers, +-- | Helper function to replace empty input names with a sequence of numbers, -- to get each input date an unique identifier replaceEmptyNames :: [CalExpr] -> [CalExpr] replaceEmptyNames = zipWith (replaceName . show) ([1..] :: [Integer])@@ -109,7 +110,7 @@ if name == "unknownSampleName" then UnCalDate $ UncalC14 i x y else UnCalDate $ UncalC14 name x y- replaceName i (CalDate (CalPDF name x y)) = + replaceName i (CalDate (CalPDF name x y)) = if name == "unknownSampleName" then CalDate $ CalPDF i x y else CalDate $ CalPDF name x y
src/Currycarbon/CalCurves/Intcal20.hs view
@@ -1,7 +1,7 @@ module Currycarbon.CalCurves.Intcal20 where -import Currycarbon.Parsers ( readCalCurve )-import Currycarbon.Types ( CalCurveBP )+import Currycarbon.Parsers (readCalCurve)+import Currycarbon.Types (CalCurveBP) -- | The intcal20 calibration curve -- (Reimer et al. 2020, doi: [10.1017/RDC.2020.41](https://doi.org/10.1017/RDC.2020.41))
src/Currycarbon/Calibration/Bchron.hs view
@@ -2,19 +2,19 @@ module Currycarbon.Calibration.Bchron (calibrateDateBchron) where -import Currycarbon.Calibration.Utils-import Currycarbon.Parsers-import Currycarbon.Types-import Currycarbon.Utils+import Currycarbon.Calibration.Utils+import Currycarbon.Parsers+import Currycarbon.Types+import Currycarbon.Utils -import qualified Data.Vector.Unboxed as VU+import qualified Data.Vector.Unboxed as VU -- | Intercept calibration as implemented in the Bchron R package (see 'Bchron') calibrateDateBchron :: CalibrationDistribution -> Bool -> Bool -> CalCurveBP -> UncalC14 -> Either CurrycarbonException CalPDF calibrateDateBchron distr allowOutside interpolate calCurve uncalC14@(UncalC14 name age ageSd) = if not allowOutside && isOutsideRangeOfCalCurve calCurve uncalC14 then Left $ CurrycarbonCalibrationRangeException $ renderUncalC14 uncalC14- else + else let rawCalCurveSegment = getRelevantCalCurveSegment uncalC14 calCurve CalCurveBCAD cals mus tau1s = prepareCalCurveSegment interpolate rawCalCurveSegment ageFloat = -(fromIntegral age)+1950@@ -23,8 +23,8 @@ musFloat = VU.map fromIntegral mus tau1sFloat = VU.map fromIntegral tau1s dens = case distr of- NormalDist -> + NormalDist -> VU.zipWith (\mu tau1 -> dnorm 0 1 ((ageFloat - mu) / sqrt (ageSd2Float + tau1 * tau1))) musFloat tau1sFloat- StudentTDist degreesOfFreedom -> + StudentTDist degreesOfFreedom -> VU.zipWith (\mu tau1 -> dt degreesOfFreedom ((ageFloat - mu) / sqrt (ageSd2Float + tau1 * tau1))) musFloat tau1sFloat in Right $ trimLowDensityEdgesCalPDF $ normalizeCalPDF $ CalPDF name cals dens
src/Currycarbon/Calibration/Calibration.hs view
@@ -18,44 +18,45 @@ , defaultCalConf ) where -import Currycarbon.Calibration.Utils-import Currycarbon.Calibration.Bchron-import Currycarbon.Calibration.MatrixMult-import Currycarbon.Types-import Currycarbon.Utils+import Currycarbon.Calibration.Bchron+import Currycarbon.Calibration.MatrixMult+import Currycarbon.Calibration.Utils+import Currycarbon.Types+import Currycarbon.Utils -import Data.List (sort, sortBy, groupBy, elemIndex)-import Data.Maybe (fromJust)-import qualified Data.Vector.Unboxed as VU+import Data.List (elemIndex, groupBy, sort,+ sortBy)+import Data.Maybe (fromJust)+import qualified Data.Vector.Unboxed as VU -- | A data type to cover the configuration options of the calibrateDates function data CalibrateDatesConf = CalibrateDatesConf {- -- | The calibration algorithm that should be used - _calConfMethod :: CalibrationMethod+ -- | The calibration algorithm that should be used+ _calConfMethod :: CalibrationMethod -- | Allow calibration to run outside of the range of the calibration curve- , _calConfAllowOutside :: Bool+ , _calConfAllowOutside :: Bool -- | Interpolate the calibration curve before calibration. -- This is a simple linear interpolation only to increase the output -- resolution for earlier time periods, where the typical calibration -- curves are less dense by default. With the interpolation, the output- -- will be a per-year density. The mechanism is inspired by the + -- will be a per-year density. The mechanism is inspired by the -- [implementation in the Bchron R package](https://github.com/andrewcparnell/Bchron/blob/b202d18550319b488e676a8b542aba55853f6fa3/R/BchronCalibrate.R#L118-L119)- , _calConfInterpolateCalCurve :: Bool + , _calConfInterpolateCalCurve :: Bool } deriving (Show, Eq) --- | A default configuration that should yield almost identical calibration results +-- | A default configuration that should yield almost identical calibration results -- to the [Bchron R package](https://github.com/andrewcparnell/Bchron) defaultCalConf :: CalibrateDatesConf defaultCalConf = CalibrateDatesConf { _calConfMethod = Bchron { distribution = StudentTDist 100 }- , _calConfAllowOutside = False + , _calConfAllowOutside = False , _calConfInterpolateCalCurve = True } -- | Calibrates a list of dates with the provided calibration curve calibrateDates :: CalibrateDatesConf -- ^ Configuration options to consider -> CalCurveBP -- ^ A calibration curve- -> [UncalC14] -- ^ A list of uncalibrated radiocarbon dates + -> [UncalC14] -- ^ A list of uncalibrated radiocarbon dates -> [Either CurrycarbonException CalPDF] -- ^ The function returns a list for each input date, with -- either an exception if the calibration failed for some -- reason, or a 'CalPDF'@@ -69,7 +70,7 @@ calibrateDate :: CalibrateDatesConf -- ^ Configuration options to consider -> CalCurveBP -- ^ A calibration curve -> UncalC14 -- ^ An uncalibrated radiocarbon date- -> Either CurrycarbonException CalPDF -- ^ The function returns either an exception if the + -> Either CurrycarbonException CalPDF -- ^ The function returns either an exception if the -- calibration failed for some reason, or a 'CalPDF' calibrateDate (CalibrateDatesConf MatrixMultiplication allowOutside interpolate) calCurve uncalDate = calibrateDateMatrixMult allowOutside interpolate calCurve uncalDate@@ -110,17 +111,17 @@ hdrs68 = densities2HDR68 contextualizedDensities hdrs95 = densities2HDR95 contextualizedDensities -- helper functions- indexVU _ Nothing = Nothing+ indexVU _ Nothing = Nothing indexVU x (Just i) = x VU.!? i cumsumDens :: [(YearBCAD, Float)] -> [Float] cumsumDens x = scanl1 (+) $ map snd x densities2HDR68 :: [(Int, Float, Bool, Bool)] -> [HDR]- densities2HDR68 cDensities = + densities2HDR68 cDensities = let highDensityGroups = groupBy (\(_,_,in681,_) (_,_,in682,_) -> in681 == in682) cDensities filteredDensityGroups = filter (all getIn68) highDensityGroups in map (\xs -> let yearRange = map getYear xs in HDR (head yearRange) (last yearRange)) filteredDensityGroups densities2HDR95 :: [(Int, Float, Bool, Bool)] -> [HDR]- densities2HDR95 cDensities = + densities2HDR95 cDensities = let highDensityGroups = groupBy (\(_,_,_,in951) (_,_,_,in952) -> in951 == in952) cDensities filteredDensityGroups = filter (all getIn95) highDensityGroups in map (\xs -> let yearRange = map getYear xs in HDR (head yearRange) (last yearRange)) filteredDensityGroups
src/Currycarbon/Calibration/MatrixMult.hs view
@@ -6,14 +6,14 @@ , uncalToPDF ) where -import Currycarbon.Calibration.Utils-import Currycarbon.Parsers-import Currycarbon.Types-import Currycarbon.Utils+import Currycarbon.Calibration.Utils+import Currycarbon.Parsers+import Currycarbon.Types+import Currycarbon.Utils -import qualified Data.Vector.Unboxed as VU-import qualified Data.Vector as V-import Data.Vector.Generic (convert)+import qualified Data.Vector as V+import Data.Vector.Generic (convert)+import qualified Data.Vector.Unboxed as VU -- | Intercept calibration implemented with matrix multiplication (see 'MatrixMultiplication') calibrateDateMatrixMult :: Bool -> Bool -> CalCurveBP -> UncalC14 -> Either CurrycarbonException CalPDF@@ -40,15 +40,15 @@ where buildMatrix :: VU.Vector Float -> VU.Vector Float -> VU.Vector Float -> V.Vector (VU.Vector Float) buildMatrix curveuncal_ sigmas_ uncal_ =- V.map (\x -> VU.map (fillCell x) uncal_) $ + V.map (\x -> VU.map (fillCell x) uncal_) $ V.zip (convert curveuncal_) (convert sigmas_) fillCell :: (Float, Float) -> Float -> Float- fillCell (mean, sigma) matrixPosBP = + fillCell (mean, sigma) matrixPosBP = if abs (mean - matrixPosBP) < 6*sigma then dnorm mean sigma matrixPosBP else 0 --- | Transform an uncalibrated date to an uncalibrated +-- | Transform an uncalibrated date to an uncalibrated -- probability density table uncalToPDF :: UncalC14 -> UncalPDF uncalToPDF (UncalC14 name mean std) =
src/Currycarbon/Calibration/Utils.hs view
@@ -2,22 +2,22 @@ module Currycarbon.Calibration.Utils where -import Currycarbon.Types+import Currycarbon.Types -import qualified Data.Vector.Unboxed as VU-import Data.Maybe (fromMaybe)-import Numeric.SpecFunctions (logBeta)+import Data.Maybe (fromMaybe)+import qualified Data.Vector.Unboxed as VU+import Numeric.SpecFunctions (logBeta) -- | Rescale a CalPDF so that the sum of the densities is approx. 1.0 normalizeCalPDF :: CalPDF -> CalPDF-normalizeCalPDF (CalPDF name cals dens) = +normalizeCalPDF (CalPDF name cals dens) = case VU.sum dens of 0.0 -> CalPDF name cals dens -- product calibration can yield empty calPDFs s -> CalPDF name cals $ VU.map (/s) dens -- | get the density of a normal distribution at a point x-dnorm :: Float -> Float -> Float -> Float -dnorm mu sigma x = +dnorm :: Float -> Float -> Float -> Float+dnorm mu sigma x = let a = recip (sqrt (2 * pi * sigma2)) b = exp (-c2 / (2 * sigma2)) c = x - mu@@ -39,7 +39,7 @@ -- realToFrac $ density (studentT (realToFrac dof)) (realToFrac x) -- dof: number of degrees of freedom isOutsideRangeOfCalCurve :: CalCurveBP -> UncalC14 -> Bool-isOutsideRangeOfCalCurve (CalCurveBP _ uncals _) (UncalC14 _ age _) = +isOutsideRangeOfCalCurve (CalCurveBP _ uncals _) (UncalC14 _ age _) = age < VU.minimum uncals || age > VU.maximum uncals -- | Take an uncalibrated date and a raw calibration curve and return@@ -53,7 +53,7 @@ toIndex = stopIndex - startIndex in CalCurveBP (VU.slice startIndex toIndex cals) (VU.slice startIndex toIndex uncals) (VU.slice startIndex toIndex sigmas) --- | Modify a calibration curve (segment) with multiple optional steps, +-- | Modify a calibration curve (segment) with multiple optional steps, -- including interpolation and transforming dates to BC/AD format prepareCalCurveSegment :: Bool -> CalCurveBP -> CalCurveBCAD prepareCalCurveSegment interpolate calCurve =@@ -76,9 +76,9 @@ getTimeWindows xs = VU.zipWith (,) (VU.init xs) (VU.tail xs) fillTimeWindows :: ((YearBP,YearBP,YearRange),(YearBP,YearBP,YearRange)) -> VU.Vector (YearBP,YearBP,YearRange) fillTimeWindows ((calbp1,bp1,sigma1),(calbp2,bp2,sigma2)) =- if calbp1 == calbp2 || calbp1+1 == calbp2 || calbp1-1 == calbp2 + if calbp1 == calbp2 || calbp1+1 == calbp2 || calbp1-1 == calbp2 then VU.singleton (calbp1,bp1,sigma1)- else + else let newCals = VU.fromList [calbp1,calbp1-1..calbp2+1] -- range definition like this to trigger counting down newBPs = VU.map (snd . getInBetweenPointsInt (calbp1,bp1) (calbp2,bp2)) newCals newSigmas = VU.map (snd . getInBetweenPointsInt (calbp1,sigma1) (calbp2,sigma2)) newCals
src/Currycarbon/Parsers.hs view
@@ -2,21 +2,21 @@ module Currycarbon.Parsers where -import Currycarbon.Types-import Currycarbon.Utils+import Currycarbon.Types+import Currycarbon.Utils -import Control.Exception (throwIO)-import Data.List (intercalate, transpose)-import qualified Text.Parsec as P-import qualified Text.Parsec.String as P-import qualified Data.Vector.Unboxed as VU-import qualified Data.Vector as V+import Control.Exception (throwIO)+import Data.List (intercalate, transpose)+import qualified Data.Vector as V+import qualified Data.Vector.Unboxed as VU+import qualified Text.Parsec as P+import qualified Text.Parsec.String as P -- * Parsing, rendering and writing functions -- -- $importExport ----- This module contains a number of functions to manage data input and +-- This module contains a number of functions to manage data input and -- output plumbing for different datatypes -- CalibrationMethod@@ -46,26 +46,26 @@ -- | Combine 'CalExpr', 'CalPDF' and 'CalC14' to render pretty command line output -- like this:--- +-- -- @ -- DATE: (5000±30BP + 5100±100BP) -- Calibrated: 4150BC \>\> 3941BC \> 3814BC \< 3660BC \<\< 3651BC -- 1-sigma: 3941-3864BC, 3810-3707BC, 3667-3660BC -- 2-sigma: 4150-4148BC, 4048-3651BC--- ▁ --- ▒▁ ▁▁ --- ▁▁▁ ▁▒▒▁▒▒ --- ▁▁▒▒▒ ▒▒▒▒▒▒ --- ▁▁▒▒▒▒▒▁▁▁▁▒▒▒▒▒▒▁ ▁ --- ▁▁▁▁▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▁▒▁ +-- ▁+-- ▒▁ ▁▁+-- ▁▁▁ ▁▒▒▁▒▒+-- ▁▁▒▒▒ ▒▒▒▒▒▒+-- ▁▁▒▒▒▒▒▁▁▁▁▒▒▒▒▒▒▁ ▁+-- ▁▁▁▁▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▁▒▁ -- ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▁▁▁▁▁▁▁▁ -- -4330 ┄──┬─────┬─────┬─────┬──────┬─────┬─────┬─────┬─────┄ -3530--- \> \> \^ \< --- ────── ──────── ── +-- \> \> \^ \<+-- ────── ──────── ── -- ─ ────────────────────────── -- @ ---renderCalDatePretty :: +renderCalDatePretty :: Bool -- ^ Should the CLI plot be restricted to (boring) ASCII symbols? -> (CalExpr, CalPDF, CalC14) -> String@@ -119,14 +119,14 @@ s <- readFile uncalFile case P.runParser parseCalExprSepByNewline () "" s of Left err -> throwIO $ CurrycarbonCLIParsingException $ show err- Right x -> return x+ Right x -> return x where parseCalExprSepByNewline :: P.Parser [CalExpr] parseCalExprSepByNewline = P.endBy expr (P.newline <* P.spaces) <* P.eof -- CalC14 -- | Write 'CalC14's to the file system. The output file is a long .csv file with the following structure:--- +-- -- @ -- sample,hdrSigma,hdrStartBCAD,hdrStopBCAD -- Sample1,1,-3797,-3709@@ -142,15 +142,15 @@ -- Sample2,2,-1323,-1112 -- Sample2,2,-1393,-1334 -- @--- +-- writeCalC14s :: FilePath -> [CalC14] -> IO ()-writeCalC14s path calC14s = writeFile path $ - "sample,hdrSigma,hdrStartBCAD,hdrStopBCAD\n" +writeCalC14s path calC14s = writeFile path $+ "sample,hdrSigma,hdrStartBCAD,hdrStopBCAD\n" ++ intercalate "\n" (map renderCalC14ForFile calC14s) writeCalC14 :: FilePath -> CalC14 -> IO ()-writeCalC14 path calC14 = writeFile path $ - "sample,hdrSigma,hdrStartBCAD,hdrStopBCAD\n" +writeCalC14 path calC14 = writeFile path $+ "sample,hdrSigma,hdrStartBCAD,hdrStopBCAD\n" ++ renderCalC14ForFile calC14 appendCalC14 :: FilePath -> CalC14 -> IO ()@@ -159,7 +159,7 @@ renderCalC14ForFile :: CalC14 -> String renderCalC14ForFile (CalC14 name _ hdrs68 hdrs95) =- intercalate "\n" $ + intercalate "\n" $ map renderRow $ zip3 (repeat name) (repeat "1") (renderHDRsForFile hdrs68) ++ zip3 (repeat name) (repeat "2") (renderHDRsForFile hdrs95)@@ -168,8 +168,8 @@ renderRow (a, b, (c, d)) = intercalate "," [a,b,c,d] renderCalC14s :: [CalC14] -> String-renderCalC14s xs = - "Calibrated high density ranges (HDR):\n" +renderCalC14s xs =+ "Calibrated high density ranges (HDR):\n" ++ intercalate "\n" (map renderCalC14 xs) renderCalC14 :: CalC14 -> String@@ -212,7 +212,7 @@ -- CalCurveMatrix writeCalCurveMatrix :: FilePath -> CalCurveMatrix -> IO ()-writeCalCurveMatrix path calCurveMatrix = +writeCalCurveMatrix path calCurveMatrix = writeFile path $ renderCalCurveMatrix calCurveMatrix renderCalCurveMatrix :: CalCurveMatrix -> String@@ -220,12 +220,12 @@ let header = "," ++ intercalate "," (map show $ VU.toList cals) ++ "\n" body = zipWith makeRow (VU.toList uncals) (transpose $ V.toList (V.map VU.toList curveDensities)) in header ++ intercalate "\n" body- where + where makeRow uncal dens = show uncal ++ "," ++ intercalate "," (map show dens) -- CalPDF -- | Write 'CalPDF's to the file system. The output file is a long .csv file with the following structure:--- +-- -- @ -- sample,calBCAD,density -- ...@@ -240,7 +240,7 @@ -- Sample2,-3675,2.095691e-3 -- ... -- @--- +-- writeCalPDFs :: FilePath -> [CalPDF] -> IO () writeCalPDFs path calPDFs = writeFile path $@@ -266,7 +266,7 @@ where makeRow (x,y) = show name ++ "," ++ show x ++ "," ++ show y ++ "\n" -data PlotSymbol = HistFill | HistTop | AxisEnd | AxisLine | AxisTick | HDRLine +data PlotSymbol = HistFill | HistTop | AxisEnd | AxisLine | AxisTick | HDRLine renderCLIPlotCalPDF :: Bool -> Int -> Int -> CalPDF -> CalC14 -> String renderCLIPlotCalPDF ascii rows cols (CalPDF _ cals dens) c14 =@@ -364,31 +364,31 @@ renderUncalC14 (UncalC14 name bp sigma) = name ++ ":" ++ show bp ++ "±" ++ show sigma ++ "BP" -- | Read uncalibrated radiocarbon dates from a file. The file should feature one radiocarbon date--- per line in the form "\<sample name\>,\<mean age BP\>,\<one sigma standard deviation\>", where +-- per line in the form "\<sample name\>,\<mean age BP\>,\<one sigma standard deviation\>", where -- \<sample name\> is optional. A valid file could look like this:--- +-- -- @ -- Sample1,5000,30 -- 6000,50 -- Sample3,4000,25 -- @--- +-- readUncalC14FromFile :: FilePath -> IO [UncalC14] readUncalC14FromFile uncalFile = do s <- readFile uncalFile case P.runParser uncalC14SepByNewline () "" s of Left err -> throwIO $ CurrycarbonCLIParsingException $ show err- Right x -> return x+ Right x -> return x where uncalC14SepByNewline :: P.Parser [UncalC14] uncalC14SepByNewline = P.endBy parseUncalC14 (P.newline <* P.spaces) <* P.eof readUncalC14 :: String -> Either String [UncalC14]-readUncalC14 s = +readUncalC14 s = case P.runParser uncalC14SepBySemicolon () "" s of Left err -> Left $ renderCurrycarbonException $ CurrycarbonCLIParsingException $ show err Right x -> Right x- where + where uncalC14SepBySemicolon :: P.Parser [UncalC14] uncalC14SepBySemicolon = P.sepBy parseUncalC14 (P.char ';' <* P.spaces) <* P.eof @@ -411,7 +411,7 @@ -- CalCurve writeCalCurve :: FilePath -> CalCurveBCAD -> IO ()-writeCalCurve path calCurve = +writeCalCurve path calCurve = writeFile path $ renderCalCurve calCurve renderCalCurve :: CalCurveBCAD -> String@@ -422,7 +422,7 @@ where makeRow (x,y,z) = show x ++ "," ++ show y ++ "," ++ show z --- | Read a calibration curve file. The file must adhere to the current version of the +-- | Read a calibration curve file. The file must adhere to the current version of the -- .c14 file format (e.g. [here](http://intcal.org/curves/intcal20.14c)). Look -- [here](http://intcal.org/blurb.html) for other calibration curves readCalCurveFromFile :: FilePath -> IO CalCurveBP@@ -434,7 +434,7 @@ readCalCurve calCurveString = do case P.runParser parseCalCurve () "" calCurveString of Left p -> error $ "This should never happen." ++ show p- Right x -> CalCurveBP + Right x -> CalCurveBP (VU.fromList $ map (\(a,_,_) -> a) x) (VU.fromList $ map (\(_,b,_) -> b) x) (VU.fromList $ map (\(_,_,c) -> c) x)@@ -444,7 +444,7 @@ P.skipMany comments P.sepEndBy parseCalCurveLine (P.manyTill P.anyToken (P.try P.newline)) -parseCalCurveLine :: P.Parser (YearBP, YearBP, YearRange) +parseCalCurveLine :: P.Parser (YearBP, YearBP, YearRange) parseCalCurveLine = do calBP <- read <$> P.many1 P.digit _ <- P.oneOf ","@@ -454,7 +454,7 @@ return (calBP, bp, sigma) comments :: P.Parser String-comments = do +comments = do _ <- P.string "#" _ <- P.manyTill P.anyChar P.newline return ""
src/Currycarbon/SumCalibration.hs view
@@ -2,17 +2,17 @@ module Currycarbon.SumCalibration where -import Currycarbon.Types-import Currycarbon.Utils-import Currycarbon.Calibration.Calibration-import Currycarbon.Calibration.Utils+import Currycarbon.Calibration.Calibration+import Currycarbon.Calibration.Utils+import Currycarbon.Types+import Currycarbon.Utils -import Data.Foldable (foldl')-import qualified Data.Vector.Unboxed as VU-import Data.List (sortBy, groupBy)-import Data.Ord (comparing)+import Data.Foldable (foldl')+import Data.List (groupBy, sortBy)+import Data.Ord (comparing)+import qualified Data.Vector.Unboxed as VU --- | Evaluate a dating expression by calibrating the individual dates and forming the respective +-- | Evaluate a dating expression by calibrating the individual dates and forming the respective -- sums and products of post-calibration density distributions evalCalExpr :: CalibrateDatesConf -> CalCurveBP -> CalExpr -> Either CurrycarbonException CalPDF evalCalExpr conf curve calExpr = mapEither id normalizeCalPDF $ evalE calExpr@@ -21,17 +21,17 @@ evalE (UnCalDate a) = calibrateDate conf curve a evalE (CalDate a) = Right a evalE (SumCal a b) = eitherCombinePDFs (+) 0 (evalE a) (evalE b)- evalE (ProductCal a b) = mapEither id normalizeCalPDF $ eitherCombinePDFs (*) 1 + evalE (ProductCal a b) = mapEither id normalizeCalPDF $ eitherCombinePDFs (*) 1 (mapEither id normalizeCalPDF $ evalE a) (mapEither id normalizeCalPDF $ evalE b) -- product needs extra normalization -- https://hackage.haskell.org/package/either-5.0.2/docs/Data-Either-Combinators.html mapEither :: (a -> c) -> (b -> d) -> Either a b -> Either c d mapEither f _ (Left x) = Left (f x) mapEither _ f (Right x) = Right (f x) -eitherCombinePDFs :: - (Float -> Float -> Float) -> Float -> - Either CurrycarbonException CalPDF -> - Either CurrycarbonException CalPDF -> +eitherCombinePDFs ::+ (Float -> Float -> Float) -> Float ->+ Either CurrycarbonException CalPDF ->+ Either CurrycarbonException CalPDF -> Either CurrycarbonException CalPDF eitherCombinePDFs _ _ (Left e) _ = Left e eitherCombinePDFs _ _ _ (Left e) = Left e@@ -60,7 +60,7 @@ pdfGrouped = groupBy (\a b -> fst a == fst b) pdfSorted pdfRes = map foldYearGroup pdfGrouped in CalPDF (name1 ++ ":" ++ name2) (VU.fromList $ map fst pdfRes) (VU.fromList $ map snd pdfRes)- where + where getMiss :: YearBCAD -> YearBCAD -> YearBCAD -> YearBCAD -> [YearBCAD] getMiss a1 a2 b1 b2 | a1 < b1 && a2 > b2 = [a1..b1] ++ [b2..a2]
src/Currycarbon/Types.hs view
@@ -2,8 +2,8 @@ module Currycarbon.Types where +import qualified Data.Vector as V import qualified Data.Vector.Unboxed as VU-import qualified Data.Vector as V -- * Data types --@@ -11,18 +11,18 @@ -- -- This module defines the relevant data types for handling radiocarbon dates --- | Different calibration algorithms implemented in currycarbon. Currently two distinct +-- | Different calibration algorithms implemented in currycarbon. Currently two distinct -- implementations are available, although both of them are similar [Intercept calibration](https://en.wikipedia.org/wiki/Radiocarbon_calibration#Intercept) -- algorithms. Maybe more algorithms will be added in the future data CalibrationMethod = -- | A matrix multiplication method generally following [this blog post by Martin Hinz](https://www.martinhinz.info/jekyll/update/blog/2016/06/03/simple_calibration.html).- -- This method is slower and the underlying code more verbose than 'Bchron', but it + -- This method is slower and the underlying code more verbose than 'Bchron', but it -- has some advantages regarding didactics and the inspection of intermediate data -- products for debugging. -- Using this method is thus generally not advisable, except for specific applications, -- where a more technical insight into C14 calibration is needed MatrixMultiplication- -- | A fast and reliable calibration algorithm very similar to the implementation in the + -- | A fast and reliable calibration algorithm very similar to the implementation in the -- [R package Bchron by Andrew Parnell](https://github.com/andrewcparnell/Bchron/blob/master/R/BchronCalibrate.R). -- This algorithm can be run with a simple normal distribution ('NormalDist') or -- Student's t-distribution ('StudentTDist'), which is recommended@@ -30,12 +30,12 @@ deriving (Show, Eq) -- | Statistical distributions to be used with the 'CalibrationMethod' 'Bchron'-data CalibrationDistribution = +data CalibrationDistribution = -- | Normal distribution NormalDist -- | Student's t-distribution. | StudentTDist {- ndf :: Double -- ^ number of degrees of freedom + ndf :: Double -- ^ number of degrees of freedom } deriving (Show, Eq) @@ -49,9 +49,9 @@ type YearRange = Word -- | A data type to represent an uncalibrated radiocarbon date-data UncalC14 = UncalC14 { - -- | Sample identifier, e.g. a lab number - _uncalC14Id :: String+data UncalC14 = UncalC14 {+ -- | Sample identifier, e.g. a lab number+ _uncalC14Id :: String -- | C14 age in years BP , _uncalC14UnCal :: YearBP -- | C14 standard deviation (one sigma in years)@@ -62,17 +62,17 @@ -- Although technically not correct, we still call this a probability density function (PDF) data UncalPDF = UncalPDF { -- | Sample identifier, e.g. a lab number- _uncalPDFid :: String+ _uncalPDFid :: String -- | Years BP , _uncalPDFUnCals :: VU.Vector YearBP -- | Probability densities- , _uncalPDFDens :: VU.Vector Float+ , _uncalPDFDens :: VU.Vector Float } deriving Show -- | A data type to represent a calibration curve with 'YearBP' data CalCurveBP = CalCurveBP { -- | Years calBP- _calCurveBPCals :: VU.Vector YearBP+ _calCurveBPCals :: VU.Vector YearBP -- | Years BP , _calCurveBPUnCals :: VU.Vector YearBP -- | Standard deviation (one sigma in years)@@ -82,7 +82,7 @@ -- | A second data type to represent a calibration curve, here now with 'YearBCAD' data CalCurveBCAD = CalCurveBCAD { -- | Years calBCAD- _calCurveBCADCals :: VU.Vector YearBCAD+ _calCurveBCADCals :: VU.Vector YearBCAD -- | Years BCAD , _calCurveBCADUnCals :: VU.Vector YearBCAD -- | Standard deviation (one sigma in years)@@ -94,16 +94,16 @@ -- | Row names of the calibration curve matrix: Years BCAD _calCurveMatrixUnCals :: VU.Vector YearBCAD -- | Column names of the calibration curve matrix: Years calBCAD- , _calCurveMatrixCals :: VU.Vector YearBCAD+ , _calCurveMatrixCals :: VU.Vector YearBCAD -- | Matrix (as a list of columns) with the probability densities- , _calCurveMatrixDens :: V.Vector (VU.Vector Float)+ , _calCurveMatrixDens :: V.Vector (VU.Vector Float) } deriving Show -- | A data type to represent a year-wise probability density for calibrated dates. -- Although technically not correct, we still call this a probability density function (PDF) data CalPDF = CalPDF { -- | Sample identifier, e.g. a lab number- _calPDFid :: String+ _calPDFid :: String -- | Years calBCAD , _calPDFCals :: VU.Vector YearBCAD -- | Probability densities for each year in '_calPDFCals'@@ -122,16 +122,16 @@ -- | A data type to represent a human readable summary of a calibrated radiocarbon date data CalC14 = CalC14 { -- | Identifier, e.g. a lab number- _calC14id :: String+ _calC14id :: String -- | Summary of the range of the calibrated date , _calC14RangeSummary :: CalRangeSummary -- | One-sigma high density regions- , _calC14HDROneSigma :: [HDR]+ , _calC14HDROneSigma :: [HDR] -- | Two-sigma high density regions- , _calC14HDRTwoSigma :: [HDR]+ , _calC14HDRTwoSigma :: [HDR] } deriving Show --- | A data type to store a simple range summary of the calibrated date, including +-- | A data type to store a simple range summary of the calibrated date, including -- the median age data CalRangeSummary = CalRangeSummary { -- | Start of the two-sigma age range@@ -147,12 +147,12 @@ } deriving Show -- | A data type to represent a high density region of a probability distribution.--- A high density region is here defined as an age range, within which the respective --- cummulative probability (e.g. of an calibrated radiocarbon date density curve) +-- A high density region is here defined as an age range, within which the respective+-- cummulative probability (e.g. of an calibrated radiocarbon date density curve) -- is above a certain threshold data HDR = HDR { -- | Start of the high density region in years calBCAD _hdrstart :: YearBCAD -- | End of the high density region in years calBCAD- , _hdrstop :: YearBCAD+ , _hdrstop :: YearBCAD } deriving (Show, Eq)
src/Currycarbon/Utils.hs view
@@ -3,19 +3,19 @@ renderCurrycarbonException ) where -import Control.Exception (Exception)+import Control.Exception (Exception) -- | Different exceptions for currycarbon data CurrycarbonException = CurrycarbonCLIParsingException String -- ^ An exception to describe an issue in the currycarbon CLI input parsing- | CurrycarbonCalibrationRangeException String -- ^ An exection to describe the case that a + | CurrycarbonCalibrationRangeException String -- ^ An exection to describe the case that a -- date is not in the range of the supplied calibration curve deriving (Show) instance Exception CurrycarbonException -renderCurrycarbonException :: CurrycarbonException -> String -renderCurrycarbonException (CurrycarbonCLIParsingException s) = +renderCurrycarbonException :: CurrycarbonException -> String+renderCurrycarbonException (CurrycarbonCLIParsingException s) = "<!> Error: Input can not be parsed\n" ++ s renderCurrycarbonException (CurrycarbonCalibrationRangeException s) = s ++ " <!> Error: Date outside of calibration range"