2024-06-09 20:00:49 +00:00
|
|
|
defmodule Growth do
|
|
|
|
@moduledoc """
|
|
|
|
Follow up child growth from 0 to 19 years, calculating z-scores for the following measurements:
|
|
|
|
|
|
|
|
* weight between ages 0 and 10 years
|
|
|
|
* height between ages 0 and 19 years
|
|
|
|
* body mass index (bmi) between ages 0 and 19 years
|
|
|
|
* head circumference between ages 0 and 5 years
|
|
|
|
* arm circumference between ages 3 months and 5 years
|
|
|
|
* subscapular skinfold between ages 3 months and 5 years
|
|
|
|
* triceps skinfold between ages 3 months and 5 years
|
|
|
|
"""
|
|
|
|
|
|
|
|
alias __MODULE__.Calc.Age
|
|
|
|
alias __MODULE__.Calc.BMI
|
2024-06-11 11:42:57 +00:00
|
|
|
alias __MODULE__.Score
|
2024-06-09 20:00:49 +00:00
|
|
|
|
|
|
|
@type gender :: :male | :female
|
|
|
|
|
|
|
|
@type measure :: number() | nil
|
|
|
|
|
|
|
|
@type opts :: [
|
|
|
|
date_of_measurement: Date.t(),
|
|
|
|
weight: measure(),
|
|
|
|
height: measure(),
|
|
|
|
arm_circumference: measure(),
|
|
|
|
head_circumference: measure(),
|
|
|
|
subscapular_skinfold: measure(),
|
|
|
|
triceps_skinfold: measure()
|
|
|
|
]
|
|
|
|
|
|
|
|
@type t :: %__MODULE__{
|
|
|
|
name: String.t(),
|
|
|
|
gender: gender(),
|
|
|
|
date_of_birth: Date.t(),
|
|
|
|
date_of_measurement: Date.t(),
|
|
|
|
age_in_days: pos_integer(),
|
|
|
|
age_in_weeks: pos_integer(),
|
|
|
|
age_in_months: pos_integer(),
|
|
|
|
weight: measure(),
|
|
|
|
height: measure(),
|
|
|
|
arm_circumference: measure(),
|
|
|
|
head_circumference: measure(),
|
|
|
|
subscapular_skinfold: measure(),
|
|
|
|
triceps_skinfold: measure(),
|
|
|
|
bmi: measure(),
|
|
|
|
results: list()
|
|
|
|
}
|
|
|
|
|
|
|
|
@enforce_keys [:name, :gender, :date_of_birth]
|
|
|
|
defstruct [
|
|
|
|
:name,
|
|
|
|
:gender,
|
|
|
|
:date_of_birth,
|
|
|
|
:date_of_measurement,
|
|
|
|
:age_in_days,
|
|
|
|
:age_in_weeks,
|
|
|
|
:age_in_months,
|
|
|
|
:weight,
|
|
|
|
:height,
|
|
|
|
:arm_circumference,
|
|
|
|
:head_circumference,
|
|
|
|
:subscapular_skinfold,
|
|
|
|
:triceps_skinfold,
|
|
|
|
:bmi,
|
|
|
|
:results
|
|
|
|
]
|
|
|
|
|
|
|
|
@valid_measures [
|
|
|
|
:date_of_measurement,
|
|
|
|
:weight,
|
|
|
|
:height,
|
|
|
|
:arm_circumference,
|
|
|
|
:head_circumference,
|
|
|
|
:subscapular_skinfold,
|
|
|
|
:triceps_skinfold
|
|
|
|
]
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Create a new growth measurement for a children with name, gender, date of birth, and the following optional arguments:
|
|
|
|
|
|
|
|
* `:date_of_measurement`: date when the measures were collected, defaults to today.
|
|
|
|
* `:weight`: weight in kilograms, defaults to `nil`.
|
|
|
|
* `:height`: height in centimeters, defaults to `nil`.
|
|
|
|
* `:arm_circumference`: arm circumference in centimeters, defaults to `nil`.
|
|
|
|
* `:head_circumference`: head circumference in centimeters, defaults to `nil`.
|
|
|
|
* `:subscapular_skinfold`: subscapular skinfold in milimeters, defaults to `nil`.
|
|
|
|
* `:triceps_skinfold`: triceps skinfold in milimeters, defaults to `nil`.
|
|
|
|
|
2024-06-11 12:01:50 +00:00
|
|
|
## Examples
|
|
|
|
|
|
|
|
iex> Growth.new(
|
|
|
|
...> "child a",
|
|
|
|
...> :male,
|
|
|
|
...> ~D[2024-01-01],
|
|
|
|
...> date_of_measurement: ~D[2024-04-01],
|
|
|
|
...> weight: 8,
|
|
|
|
...> height: 65.4,
|
|
|
|
...> arm_circumference: 15.5,
|
|
|
|
...> head_circumference: 42.8,
|
|
|
|
...> subscapular_skinfold: 10.9,
|
|
|
|
...> triceps_skinfold: 13.5
|
|
|
|
...> )
|
|
|
|
%Growth{
|
|
|
|
name: "child a",
|
|
|
|
gender: :male,
|
|
|
|
date_of_birth: ~D[2024-01-01],
|
|
|
|
date_of_measurement: ~D[2024-04-01],
|
|
|
|
age_in_days: 91,
|
|
|
|
age_in_weeks: 13,
|
|
|
|
age_in_months: 2,
|
|
|
|
weight: 8,
|
|
|
|
height: 65.4,
|
|
|
|
arm_circumference: 15.5,
|
|
|
|
head_circumference: 42.8,
|
|
|
|
subscapular_skinfold: 10.9,
|
|
|
|
triceps_skinfold: 13.5,
|
|
|
|
bmi: 18.703999850368,
|
|
|
|
results: [
|
|
|
|
%{
|
|
|
|
head_circumference: [
|
|
|
|
{"day", {1.945484886994137, 42.800000000000004}},
|
|
|
|
{"week", {1.945484886994137, 42.800000000000004}},
|
|
|
|
{"month", {3.130859582465616, :na}}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
%{arm_circumference: [{"day", {1.9227031505630465, 15.499999999999996}}]},
|
|
|
|
%{subscapular_skinfold: [{"day", {1.9437372448689536, 10.9}}]},
|
|
|
|
%{triceps_skinfold: [{"day", {1.950277062993091, 13.500000000000353}}]},
|
|
|
|
%{
|
|
|
|
weight: [
|
|
|
|
{"day", {1.982458622036091, 8.0}},
|
|
|
|
{"week", {1.982458622036091, 8.0}},
|
|
|
|
{"month", {3.0355951313091745, :na}}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
%{
|
|
|
|
height: [
|
|
|
|
{"day", {1.956263992749136, 65.4}},
|
|
|
|
{"week", {1.956263992749136, 65.4}},
|
|
|
|
{"month", {3.4867331002754054, :na}}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
%{
|
|
|
|
bmi: [
|
|
|
|
{"day", {1.1977344927294398, 18.703999850368085}},
|
|
|
|
{"week", {1.1977344927294398, 18.703999850368085}},
|
|
|
|
{"month", {1.5837461190318038, 18.703999850367996}}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
2024-06-09 20:00:49 +00:00
|
|
|
"""
|
|
|
|
@spec new(String.t(), gender(), Date.t(), opts()) :: t()
|
|
|
|
def new(name, gender, date_of_birth, opts \\ []) do
|
|
|
|
default_opts()
|
|
|
|
|> Enum.reduce(
|
|
|
|
%__MODULE__{
|
|
|
|
name: name,
|
|
|
|
gender: gender,
|
2024-06-10 18:35:12 +00:00
|
|
|
date_of_birth: date_of_birth,
|
|
|
|
results: []
|
2024-06-09 20:00:49 +00:00
|
|
|
},
|
|
|
|
fn {key, default_value}, measurement ->
|
|
|
|
opts
|
|
|
|
|> Keyword.get(key, default_value)
|
|
|
|
|> then(&Map.put(measurement, key, &1))
|
|
|
|
end
|
|
|
|
)
|
|
|
|
|> with_age_in_days()
|
|
|
|
|> with_age_in_weeks()
|
|
|
|
|> with_age_in_months()
|
|
|
|
|> with_bmi()
|
2024-06-11 11:42:57 +00:00
|
|
|
|> with_results()
|
2024-06-09 20:00:49 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
for precision <- [:day, :week, :month] do
|
|
|
|
@doc """
|
|
|
|
Add age with given precision in growth measurement.
|
|
|
|
"""
|
|
|
|
@spec unquote(:"with_age_in_#{precision}s")(t()) :: t()
|
|
|
|
|
|
|
|
def unquote(:"with_age_in_#{precision}s")(
|
|
|
|
%__MODULE__{date_of_birth: date_of_birth, date_of_measurement: date_of_measurement} =
|
|
|
|
growth
|
|
|
|
)
|
|
|
|
when not is_nil(date_of_birth) and not is_nil(date_of_measurement) do
|
|
|
|
age = Age.calculate(unquote(precision), date_of_birth, date_of_measurement)
|
|
|
|
Map.put(growth, unquote(:"age_in_#{precision}s"), age)
|
|
|
|
end
|
|
|
|
|
|
|
|
def unquote(:"with_age_in_#{precision}s")(%__MODULE__{date_of_birth: date_of_birth} = growth)
|
|
|
|
when not is_nil(date_of_birth) do
|
|
|
|
unquote(:"with_age_in_#{precision}s")(%{growth | date_of_measurement: Date.utc_today()})
|
|
|
|
end
|
|
|
|
|
|
|
|
def unquote(:"with_age_in_#{precision}s")(growth) do
|
|
|
|
growth
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def with_bmi(%__MODULE__{weight: weight, height: height} = growth)
|
|
|
|
when is_number(weight) and is_number(height) do
|
|
|
|
%{growth | bmi: BMI.calculate(:metric, weight, height)}
|
|
|
|
end
|
|
|
|
|
|
|
|
def with_bmi(growth) do
|
|
|
|
growth
|
|
|
|
end
|
|
|
|
|
2024-06-11 11:42:57 +00:00
|
|
|
def with_results(growth) do
|
|
|
|
Score.Scorer.results(growth, [
|
|
|
|
Score.BMI,
|
|
|
|
Score.Height,
|
|
|
|
Score.Weight,
|
|
|
|
Score.TricepsSkinfold,
|
|
|
|
Score.SubscapularSkinfold,
|
|
|
|
Score.ArmCircumference,
|
|
|
|
Score.HeadCircumference
|
|
|
|
])
|
|
|
|
end
|
|
|
|
|
2024-06-09 20:00:49 +00:00
|
|
|
defp default_opts do
|
|
|
|
Enum.map(@valid_measures, fn
|
|
|
|
:date_of_measurement = key ->
|
|
|
|
{key, Date.utc_today()}
|
|
|
|
|
|
|
|
key ->
|
|
|
|
{key, nil}
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
end
|