示例#1
0
 def _extract_nutrients(self, available):
     consumed = Nutrients()
     uptake_quantity = self._calculate_uptake_rate() * self._timestep
     internaliseN, internaliseC = self._interalise_choices()	 # Which elements can be internalised?
     if internaliseN:
         consumed.Nf = min(available.Nf, uptake_quantity)
     if internaliseC:
         consumed.Cm = min(available.Cm, uptake_quantity)
     return consumed
示例#2
0
 def __init__(self,
              dailyCw,
              dailyCd,
              dailyCs,
              dailyNf,
              dailyCellulose,
              regimen_start_h=0.,
              regimen_end_h=math.inf):
     """
     The daily* args specify the quantities of wheatstarch, dextrinised starch and protein that are consumed by the
     mouse each day.
     """
     super(Constant, self).__init__(regimen_start_h=regimen_start_h,
                                    regimen_end_h=regimen_end_h)
     self.daily_intake = Nutrients(Cw=dailyCw,
                                   Cd=dailyCd,
                                   Cs=dailyCs,
                                   Nf=dailyNf)
     self.dailyCw = dailyCw
     self.dailyCd = dailyCd
     self.dailyCs = dailyCs
     self.dailyNf = dailyNf
     self.dailyCellulose = dailyCellulose
     self.colicCw = dailyCw - si_absorption_wheatstarch(
         dailyCw)  # daily nutrient quantities secreted into colon
     self.colicCd = dailyCd - si_absorption_dextrinised(dailyCd)
     self.colicCs = dailyCs - si_absorption_sucrose(dailyCs)
     self.colicNf = dailyNf - si_absorption_protein(dailyNf)
     self.colicCellulose = dailyCellulose
     # daily quantity of nutrients absorbed by the small intestine.
     self.calculate_SI_behaviour(dailyCw=dailyCw,
                                 dailyCd=dailyCd,
                                 dailyCs=dailyCs,
                                 dailyNf=dailyNf)
示例#3
0
 def getNutrients(self, time, timestep):
     """
     Returns the nutrient input from the small intestine to the colin given the specified current time. The
     timestep is also supplied as the period of time that has passed. Note that the timestep should be given as a
     proportion of an hour, not a day.
     """
     time = float(time)
     day_cycle = time % 24.0
     if day_cycle < 12.0:  # Nighttime.
         inputCw = self._nighttime_hourly(self.colicCw)
         inputCd = self._nighttime_hourly(self.colicCd)
         inputNf = self._nighttime_hourly(self.colicNf)
         inputCellulose = self._nighttime_hourly(self.colicCellulose)
     else:  # Daytime
         inputCw = self._daytime_hourly(self.colicCw)
         inputCd = self._daytime_hourly(self.colicCd)
         inputNf = self._daytime_hourly(self.colicNf)
         inputCellulose = self._daytime_hourly(self.colicCellulose)
     # Convert from hourly rates to whatever the time-step is.
     inputCw *= timestep
     inputCd *= timestep
     inputNf *= timestep
     inputCellulose *= timestep
     return Nutrients(Cw=inputCw,
                      Cd=inputCd,
                      Nf=inputNf,
                      non_ferm=inputCellulose)
示例#4
0
    def initialise_nutrient_Store(self, timestep, run_time):
        """
        Sets up the nutrient store along the GIT such that it appears to have been running for ages.

        :param run_time: given in hours.
        """
        self._nutrientStores = []
        currentTime = 0.0
        while currentTime < run_time:
            currentTime += timestep
            # Nutrients added
            nutStore = Nutrients()
            for ni in self.nutrientInputs:
                nutStore.add(ni.getNutrients(currentTime, timestep))
            self._nutrientStores.insert(0,
                                        nutStore)  # Prepend to start of gut.
示例#5
0
 def getNutrients(self, time, timestep):
     time = float(time)
     day_cycle = time % 24.0
     if day_cycle < 12.0:  # nighttime, active phase
         inputCi = self._nighttime_hourly(self.colicCi)
     else:  # daytime, subdued phase
         inputCi = self._daytime_hourly(self.colicCi)
     inputCi *= timestep
     return Nutrients(Ci=inputCi)
示例#6
0
    def __init__(self,
                 dailyCw,
                 dailyCd,
                 dailyCs,
                 dailyNf,
                 dailyCellulose,
                 dailyCi,
                 dailyCi_inverse,
                 start_time,
                 colicInputDuration,
                 regimen_start_h=0.,
                 regimen_end_h=math.inf):
        """
        The daily* args specify the quantities of wheatstarch, dextrinised startch and protein that are consumed by the
        mouse each day. ColicInputDuration specifies the duration of time for which nutrients are passed from the small
        intestine into the colon.
        """
        super(TRF, self).__init__(regimen_start_h=regimen_start_h,
                                  regimen_end_h=regimen_end_h)
        self.daily_intake = Nutrients(Cw=dailyCw,
                                      Cd=dailyCd,
                                      Cs=dailyCs,
                                      Nf=dailyNf,
                                      Ci=dailyCi)
        self.colicInputDuration = colicInputDuration
        self.start_time = start_time
        self.end_time = (
            self.start_time + colicInputDuration
        ) % 24.0  # modulo in case feeding period spans 24h cycle
        self.dailyCw = dailyCw
        self.dailyCd = dailyCd
        self.dailyCs = dailyCs
        self.dailyNf = dailyNf
        self.colicCw = dailyCw - si_absorption_wheatstarch(
            dailyCw)  # Daily quantities of nutrients secreted into colon.
        self.colicCd = dailyCd - si_absorption_dextrinised(dailyCd)
        self.colicCs = dailyCs - si_absorption_sucrose(dailyCs)
        self.colicNf = dailyNf - si_absorption_protein(dailyNf)
        self.colicCi = dailyCi  # Inulin is non-digestible
        self.colicCi_inverse = dailyCi_inverse - 0.0  # Inulin is non-digestible.
        self.colicCellulose = dailyCellulose
        self.hourlyCw = self.colicCw / self.colicInputDuration
        self.hourlyCd = self.colicCd / self.colicInputDuration
        self.hourlyNf = self.colicNf / self.colicInputDuration
        self.hourlyCi = self.colicCi / self.colicInputDuration
        self.hourlyCi_inverse = self.colicCi_inverse / (
            24.0 - self.colicInputDuration)
        self.hourlyCellulose = self.colicCellulose / self.colicInputDuration

        # Daily quantity of nutrients absorbed by the small intestine.
        self.calculate_SI_behaviour(dailyCw=dailyCw,
                                    dailyCd=dailyCd,
                                    dailyCs=dailyCs,
                                    dailyNf=dailyNf)
示例#7
0
 def calculate_SI_behaviour(self, dailyCw, dailyCd, dailyCs, dailyNf):
     """ Daily quantity of nutrients absorbed by the small intestine. """
     self.daily_si_absorbed = Nutrients(
         Cw=si_absorption_wheatstarch(dailyCw),
         Cd=si_absorption_dextrinised(dailyCd),
         Cs=si_absorption_sucrose(dailyCs),
         Nf=si_absorption_protein(dailyNf))
     self.daily_colic_input = Nutrients(
         Cw=dailyCw - self.daily_si_absorbed.Cw,
         Cd=dailyCd - self.daily_si_absorbed.Cd,
         Cs=dailyCs - self.daily_si_absorbed.Cs,
         Nf=dailyNf - self.daily_si_absorbed.Nf)
     # Conditional assignments to avoid div by zero
     prop_Cw = self.daily_si_absorbed.Cw / self.daily_intake.Cw if self.daily_intake.Cw != 0 else 0
     prop_Cd = self.daily_si_absorbed.Cd / self.daily_intake.Cd if self.daily_intake.Cd != 0 else 0
     prop_Cs = self.daily_si_absorbed.Cs / self.daily_intake.Cs if self.daily_intake.Cs != 0 else 0
     prop_Nf = self.daily_si_absorbed.Nf / self.daily_intake.Nf if self.daily_intake.Nf != 0 else 0
     self.si_absorption_prop = Nutrients(Cw=prop_Cw,
                                         Cd=prop_Cd,
                                         Cs=prop_Cs,
                                         Nf=prop_Nf)
示例#8
0
    def __init__(self,
                 Cw5,
                 Cd5,
                 Cs5,
                 Nf5,
                 cellulose5,
                 fastProp,
                 fast1,
                 fast2,
                 regimen_start_h=0.,
                 regimen_end_h=math.inf):
        """
        Arguments:
          Cw5, Cd5, Nf5 - the quantities of wheatstarch, dextrinised starch and protein consumed on a non-diet day.
          fast1 - which day of the week (numbered 1-7) constitutes the first fast day
          fast2 - same but for second fast day.
          fastProp - the proportion of a normal diet eaten on a fasting day (between 0 and 1).
        """
        super(FiveTwo, self).__init__(regimen_start_h=regimen_start_h,
                                      regimen_end_h=regimen_end_h)
        self.daily_intake = Nutrients(Cw=Cw5, Cd=Cd5, Cs=Cs5, Nf=Nf5)

        self._dailyCw5 = Cw5 - si_absorption_wheatstarch(Cw5)
        self._dailyCd5 = Cd5 - si_absorption_dextrinised(Cd5)
        self._dailyCs5 = Cs5 - si_absorption_sucrose(Cs5)
        self._dailyNf5 = Nf5 - si_absorption_protein(Nf5)
        self._dailyCellulose5 = cellulose5

        # Calculate diet day nutrient secretions into the colon.
        Cw2 = fastProp * Cw5
        Cd2 = fastProp * Cd5
        Nf2 = fastProp * Nf5
        cellulose2 = fastProp * cellulose5
        self._dailyCw2 = Cw2 - si_absorption_wheatstarch(Cw2)
        self._dailyCd2 = Cd2 - si_absorption_dextrinised(Cd2)
        self._dailyNf2 = Nf2 - si_absorption_protein(Nf2)
        self._dailyCellulose2 = cellulose2
        # Start time is inclusive, end time is exclusive. Ie, if end = 24h, then on hour 24 feeding stops.
        self._fast1Start = 24.0 * (
            fast1 - 1)  # minus 1 here so first day of week is zero.
        self._fast1End = (24.0 * fast1
                          )  # 1 hour before the start of the next day.
        self._fast2Start = 24.0 * (
            fast2 - 1)  # minus 1 here so first day of week is zero.
        self._fast2End = (24.0 * fast2
                          )  # 1 hour before the start of the next day.
        # daily quantity of nutrients absorbed by the small intestine.
        self.calculate_SI_behaviour(dailyCw=Cw5,
                                    dailyCd=Cd5,
                                    dailyCs=Cs5,
                                    dailyNf=Nf5)
示例#9
0
    def getNutrients(self, time, timestep):
        """
        Returns the nutrient input from the small intestine to the colin given the specified current time. The
        timestep is also supplied as the period of time that has passed. Note that the timestep should be given as a
        proportion of an hour, not a day.
        """
        time = float(time)
        day_cycle = time % 24.0
        two_day_cycle = time % 48.0
        # First, check if day or night time.
        if day_cycle < 12.0:  # Nighttime.
            inputCw = self._nighttime_hourly(self.colicCw)
            inputCd = self._nighttime_hourly(self.colicCd)
            inputNf = self._nighttime_hourly(self.colicNf)
            inputCi = self._nighttime_hourly(self.colicCi)
            inputCi_inverse = self._nighttime_hourly(self.colicCi_inverse)
            inputCellulose = self._nighttime_hourly(self.colicCellulose)
        else:  # Daytime
            inputCw = self._daytime_hourly(self.colicCw)
            inputCd = self._daytime_hourly(self.colicCd)
            inputNf = self._daytime_hourly(self.colicNf)
            inputCi = self._daytime_hourly(self.colicCi)
            inputCi_inverse = self._daytime_hourly(self.colicCi_inverse)
            inputCellulose = self._daytime_hourly(self.colicCellulose)
        # Next, check if current time is fasting day
        if 24.0 <= two_day_cycle:
            inputCw *= self.fastProp
            inputCd *= self.fastProp
            inputNf *= self.fastProp
            inputCi = 0.0  # on fasting days, give no inulin.
            inputCellulose += self.fastProp
        else:  # Feeding day.
            inputCi_inverse = 0.0  # On feeding days, give no inulin.

        # Lastly, convert from hourly rates to whatever the time-step is.
        inputCw *= timestep
        inputCd *= timestep
        inputNf *= timestep
        inputCi *= timestep
        inputCi_inverse *= timestep
        inputCellulose *= timestep

        inputCi += inputCi_inverse  # Combine at this point, and deliver to mouse.
        return Nutrients(Cw=inputCw,
                         Cd=inputCd,
                         Nf=inputNf,
                         Ci=inputCi,
                         non_ferm=inputCellulose)
示例#10
0
 def getNutrients(self, time, timestep):
     """
     Returns the prebiotic input given the specified current time. The timestep is also supplied as the period of time that has passed.
     Note that the timestep should be given as a proportion of an hour, not a day.
     """
     time = float(time)
     cycleTime = time % 24.0  # how far through the feeding cycle we are
     # default cases if no input from small intestine
     inputCi = 0.0
     # two cases. 1) start time is smaller than end time (easy).
     # 2) the feeding period spans the 24h modulo point, in which case the end time will be smaller than the start
     # time; feeding is defined by being greater than the start time or smaller than the end time.
     if self.start_time <= cycleTime < self.end_time or \
         self.end_time <= self.start_time and (self.start_time <= cycleTime or cycleTime < self.end_time):
         inputCi = self.hourlyCi * timestep
     return Nutrients(Ci=inputCi)
示例#11
0
    def step(self, environment):
        """
        Called within the mouse simulator to step the bacteria through its states.
        """
        if self.dead:
            return Nutrients(), None  # Dead bacteria don't do anything.
        available = environment.clone()

        self._nutrient_decay()  # The cell consumes nutrients, at a decreasing rate (as it enters stress response).
        internalised = self._internalise_nutrients(available)  # Cell consumes resources from the environment.
        self._limiting_resource = self._calculate_limiting_resource()
        child = None
        if self._decide_divide(self._limiting_resource):
            child = self._divide()
        if self._decide_die(self._limiting_resource):
            self._perform_die()
        return internalised, child
示例#12
0
 def __init__(self,
              dailyCm,
              dailyNm,
              regimen_start_h=0.,
              regimen_end_h=math.inf):
     super(Mucin, self).__init__(regimen_start_h=regimen_start_h,
                                 regimen_end_h=regimen_end_h)
     self.daily_intake = Nutrients(Cm=dailyCm, Nm=dailyNm)
     # convert daily mucus secretions into hourly quantities.
     self.dailyCm = dailyCm
     self.dailyNm = dailyNm
     self.hourlyCm = dailyCm / 24.0
     self.hourlyNm = dailyNm / 24.0
     self.calculate_SI_behaviour(dailyCw=0.0,
                                 dailyCd=0.0,
                                 dailyCs=0.0,
                                 dailyNf=0.0)
     self.daily_colic_input.Cm = dailyCm
     self.daily_colic_input.Nm = dailyNm
示例#13
0
    def __init__(self,
                 dailyCw,
                 dailyCd,
                 dailyCs,
                 dailyNf,
                 dailyCellulose,
                 dailyCi,
                 dailyCi_inverse,
                 fastProp,
                 regimen_start_h=0.,
                 regimen_end_h=math.inf):
        """
        The daily* args specify the quantities of wheat starch, dextrinised starch and protein that are consumed by the
        mouse each day. ColicInputDuration specifies the duration of time for which nutrients are passed from the small
        intestine into the colon.
        """
        super(AlternateDay, self).__init__(regimen_start_h=regimen_start_h,
                                           regimen_end_h=regimen_end_h)
        self.daily_intake = Nutrients(Cw=dailyCw,
                                      Cd=dailyCd,
                                      Cs=dailyCs,
                                      Nf=dailyNf,
                                      Ci=dailyCi,
                                      non_ferm=dailyCellulose)

        self.colicCw = dailyCw - si_absorption_wheatstarch(
            dailyCw)  # Daily quantities of nutrients secreted into colon.
        self.colicCd = dailyCd - si_absorption_dextrinised(dailyCd)
        self.colicCs = dailyCs - si_absorption_sucrose(dailyCs)
        self.colicNf = dailyNf - si_absorption_protein(dailyNf)
        self.colicCi = dailyCi  # Inulin is non-digestible
        self.colicCi_inverse = dailyCi_inverse  # Inulin is non-digestible.
        self.colicCellulose = dailyCellulose  # Non-digestible.
        self.fastProp = fastProp  # Alter the proportion of nutrients available between 0 and 1
        # daily quantity of nutrients absorbed by the small intestine.
        self.calculate_SI_behaviour(dailyCw=dailyCw,
                                    dailyCd=dailyCd,
                                    dailyCs=dailyCs,
                                    dailyNf=dailyNf)
示例#14
0
    def getNutrients(self, time, timestep):
        """
        Returns the nutrient input from the small intestine to the colin given the specified current time. The
        timestep is also supplied as the period of time that has passed. Note that the timestep should be given as a
        proportion of an hour, not a day.
        """
        cycle_week = time % 168.0  # How far through the week the current time is, in hours.
        # Defaults, adjusted as needed.
        dailyCw = self._dailyCw5  # Assume on a non-fast day to begin with.
        dailyCd = self._dailyCd5
        dailyNf = self._dailyNf5
        dailyCellulose = self._dailyCellulose5
        if self._in_fast1(cycle_week) or self._in_fast2(
                cycle_week):  # Check for 2-day diet.
            dailyCw = self._dailyCw2
            dailyCd = self._dailyCd2
            dailyNf = self._dailyNf2
            dailyCellulose = self._dailyCellulose2

        cycle24 = time % 24.0
        if cycle24 < 12.0:  # Nighttime
            hourlyCw = self._nighttime_hourly(dailyCw)
            hourlyCd = self._nighttime_hourly(dailyCd)
            hourlyNf = self._nighttime_hourly(dailyNf)
            hourlyCellulose = self._nighttime_hourly(dailyCellulose)
        else:  # Daytime
            hourlyCw = self._daytime_hourly(dailyCw)
            hourlyCd = self._daytime_hourly(dailyCd)
            hourlyNf = self._daytime_hourly(dailyNf)
            hourlyCellulose = self._daytime_hourly(dailyCellulose)
        inputCw = hourlyCw * timestep
        inputCd = hourlyCd * timestep
        inputNf = hourlyNf * timestep
        inputCellulose = hourlyCellulose * timestep
        return Nutrients(Cw=inputCw,
                         Cd=inputCd,
                         Nf=inputNf,
                         non_ferm=inputCellulose)
示例#15
0
    def getNutrients(self, time, timestep):
        """
        Returns the nutrient input from the small intestine to the colin given the specified current time. The
        timestep is also supplied as the period of time that has passed. Note that the timestep should be given as a
        proportion of an hour, not a day.
        """
        feedingPeriod = 24.0
        time = float(time)
        cycleTime = time % 24.0  # How far through the feeding cycle we are
        # Default cases if no input from small intestine
        inputCw = 0.0
        inputCd = 0.0
        inputNf = 0.0
        inputCi = 0.0
        inputCi_inverse = 0.0
        inputCellulose = 0.
        # Two cases. 1) start time is smaller than end time (easy).
        # 2) the feeding period spans the 24h modulo point, in which case the end time will be smaller than the start
        # time; feeding is defined by being greater than the start time or smaller than the end time.
        if self.start_time <= cycleTime < self.end_time or \
            self.end_time <= self.start_time and (self.start_time <= cycleTime or cycleTime < self.end_time):

            inputCw = self.hourlyCw * timestep
            inputCd = self.hourlyCd * timestep
            inputNf = self.hourlyNf * timestep
            inputCi = self.hourlyCi * timestep
            inputCellulose = self.hourlyCellulose * timestep
        else:  # Fasting time
            inputCi_inverse = self.hourlyCi_inverse * timestep

        inputCi += inputCi_inverse  # Combine at this point, and deliver to mouse.
        return Nutrients(Cw=inputCw,
                         Cd=inputCd,
                         Nf=inputNf,
                         Ci=inputCi,
                         non_ferm=inputCellulose)
示例#16
0
 def getNutrients(self, time, timestep):
     inputCm = self.hourlyCm * timestep
     inputNm = self.hourlyNm * timestep
     return Nutrients(Cm=inputCm,
                      Nm=inputNm)  # nutrients not supplied default to zero.
示例#17
0
    def execute(self,
                endtime,
                timestep=0.1,
                verbose=False,
                bacteria_graphing_start_time=float('inf'),
                graphPath=None):
        """
        Called to execute this simulation of a mouse. Execution ceases after `endtime` hours.

        """
        def inoculum():
            """ Inputs new bacteria of each guild into the GIT. """
            rateDay = inoculation_rate * scale_factor
            rateHour = rateDay / 24.0
            # This gives a probability of insertion of a bug every time step.
            rateTimestep = rateHour * timestep
            new_bacteria = [
            ]  # Compile list of new bacteria, which is shuffled and then placed at start of bacteria
            # if rateTimestep > 1.0:
            #     raise Exception('Cannot insert more than 1 bug per timestep (with current code).')
            bugs_to_add = rateTimestep
            while random.random() <= bugs_to_add and init_Grf != 0:
                new_bacteria.append(
                    gutsim.bacteria.Guild_rf_f(timestep=timestep))
                bugs_to_add -= 1
            bugs_to_add = rateTimestep
            while random.random() <= bugs_to_add and init_Grm != 0:
                new_bacteria.append(
                    gutsim.bacteria.Guild_rm_m(timestep=timestep))
                bugs_to_add -= 1
            bugs_to_add = rateTimestep
            while random.random() <= bugs_to_add and init_Gpf != 0:
                new_bacteria.append(
                    gutsim.bacteria.Guild_pf_f(timestep=timestep))
                bugs_to_add -= 1
            bugs_to_add = rateTimestep
            while random.random() <= bugs_to_add and init_Gpm != 0:
                new_bacteria.append(
                    gutsim.bacteria.Guild_pm_m(timestep=timestep))
                bugs_to_add -= 1
            bugs_to_add = rateTimestep
            while random.random() <= bugs_to_add and init_Gmm != 0:
                new_bacteria.append(
                    gutsim.bacteria.Guild_m_m(timestep=timestep))
                bugs_to_add -= 1
            bugs_to_add = rateTimestep
            while random.random() <= bugs_to_add and init_Gmf != 0:
                new_bacteria.append(
                    gutsim.bacteria.Guild_mf_f(timestep=timestep))
                bugs_to_add -= 1
            shuffle(new_bacteria)  # Shuffle the additional bugs.
            new_bacteria.extend(
                self._bacteria)  # Insert new bacteria at start.
            self._bacteria = new_bacteria

        def bacteria_peristalsis():
            """
            Represents peristaliss-driven re-ordering of bacteria in gut.  The distance that the shuffling attempts to
            move each bacteria by is drawn from a gaussian distribution. The spread of the distribution can be altered
            to be rate-limited by the timestep.

            Useful literature: Roberts RR, Murphy JF, Young HM, Bornstein JC. Development of colonic motility in the
            neonatal mouse-studies using spatiotemporal maps. Am J Physiol-Gastr L. 2007;292(3):G930-G8.
            """
            # Calculate the standard deviation of locations that bacteria may be shuffled by due to peristalsis events.
            # Peristalsis presents a probability distribution representing the post-peristalsis location each bacteria
            # could end up in. This is represented by a gaussian curve, centred on each bacterium's current location.
            # start by calculating how many peristalsis events happen per time step. Gaussian standard dev represents
            # effect of shuffling, so we convert from distance in gut to number of bacteria places (they are ordered).
            # Lastly, time is accounted for.
            distance_per_bacteria = gut_length / len(self._bacteria)
            sigma = bacteria_peristalsis_rate / distance_per_bacteria  # Num of bacteria representing the desired dist.
            diffusion_rate = peristalsis_rate * timestep  # How many peristalsis events occur in each time step.
            sigma *= diffusion_rate  # Adjust for number of peristalsis events in each time step.
            # Start the shuffling.
            shuffled = [
            ]  # Will contain tuples: (post-shuffle movement, bacteria object).
            for index, bug in enumerate(self._bacteria):
                pos = float(index) + random.gauss(
                    0, sigma)  # Current position + some random quantity.
                shuffled.append((pos, bug))
            # Sorts by the first item in the tuples that the list contains.
            sort = sorted(shuffled, key=lambda tmp: tmp[0])
            self._bacteria = [tup[1] for tup in sort
                              ]  # Pull out the bacteria objects.

        def nutrient_peristalsis():
            """
            Moves nutrients between nutrient stores; a low level of mixing resulting from peristalsis. 
            """
            # Gaussian diffusion represent diffusion as a result of peristalsis, IE, how much diffusion results from
            # each peristalsis event. This variable indicates how many peristalsis events are represented in the current
            # time step (time step may represent more than one peristalsis event).
            diffusion_rate = peristalsis_rate * timestep
            sigma_time_adjusted = nutrient_peristalsis_rate * diffusion_rate
            num_nutrient_stores = len(self._nutrientStores)
            length_per_nutrient_store = gut_length / num_nutrient_stores
            # Create a new store, which will be populated with nutrients.
            new_nutrient_store = [Nutrients() for _ in self._nutrientStores]

            # Location of this store along the gut. Conceptualized as follows. Nutrient sources ordered sequentially.
            # Their locations defined as cx. For integration, need to know the lower and upper boundaries, which
            # are given in factors of l (l=length of nutrient source in the gut, and can vary with number of
            # nutrient sources).
            #
            # 0l           1l           2l           3l           4l           5l
            # -------------------------------------------------------------------
            # |    c0      |    c1      |    c2      |    c3      |    c4      | ...
            # -------------------------------------------------------------------
            #
            # Normalized gaussian curve integrates to 1, hence its integral describes the diffusion of nutrients
            # into a specified length of gut.
            # Pre-compute the diffusion quantities by index distance. This is an efficiency saving. Since the
            # distribution changes only for the number of nutrient stores, which only changes between time steps,
            # the same distribution applies for every nutrient store in a timestep.
            # Need compute only one half of the distribution, as it is symmetrical.
            diffusion_by_index_difference = [None] * len(self._nutrientStores)
            # Declared here for efficiency. The lower bound for nutrient source n+1 = the supper bound for nutrient
            # source n (so don't have to re-compute it).
            sink_upper_distance = None
            for k in range(len(self._nutrientStores)):
                loc_source = 0.5 * length_per_nutrient_store
                if sink_upper_distance is None:  # No boundaries have been calculated for first nutrient source.
                    sink_lower_distance = (
                        k * length_per_nutrient_store) - loc_source
                else:  # Adopt upper boundary of the previous nutrient source location.
                    sink_lower_distance = sink_upper_distance
                sink_upper_distance = (
                    (k + 1) * length_per_nutrient_store) - loc_source
                integral_lower = stats.phi_gauss(sink_lower_distance,
                                                 mu=0,
                                                 sigma=sigma_time_adjusted)
                integral_upper = stats.phi_gauss(sink_upper_distance,
                                                 mu=0,
                                                 sigma=sigma_time_adjusted)
                proportion_diffused = integral_upper - integral_lower
                diffusion_by_index_difference[k] = proportion_diffused
            # Diffusion only performed over ranges where a substanital difference in concentration is incurred.
            # This saves computational expense, and makes little difference to simulation dynamics.
            # Here we ascertain the distance over which (meaningful) diffusion will be performed.
            negligible_diffusion_distance = 0
            negligible_diffusion_threshold = 0.05 / len(self._nutrientStores)
            for i, diff in enumerate(diffusion_by_index_difference):
                if diff < negligible_diffusion_threshold:  # Not worth performing diffusion beyond this spatial range.
                    negligible_diffusion_distance = i
                    break

            # Scan through each existing nutrient store, and distribute nutrients
            for i, n_source in enumerate(self._nutrientStores):
                # Proportion of nutrient store contents not moved anywhere because Gaussian stretches from -Inf to Inf.
                # This will be retained in the current nutrient store location.
                remaining = 1.0
                # Start from difference of 1, 0 = the source, handled separately below.
                # Diffusion distribution is symmetrical, so calculate both sides of i (getting progressively further
                # away) simultaneously. Is more efficient, as not duplicating calculations.
                for index_difference in range(1,
                                              negligible_diffusion_distance):
                    proportion_diffused = diffusion_by_index_difference[
                        index_difference]  # use lookup table.
                    move = n_source.proportion_query(proportion_diffused)
                    i_low = i - index_difference
                    if i_low >= 0:
                        new_nutrient_store[i - index_difference].add(move)
                        remaining -= proportion_diffused
                    i_high = i + index_difference
                    if i_high <= len(self._nutrientStores) - 1:
                        new_nutrient_store[i + index_difference].add(move)
                        remaining -= proportion_diffused
                # Any nutrient not already dealt with (Gaussian stretches from -Inf to Inf) is retained
                move = n_source.proportion_query(remaining)
                new_nutrient_store[i].add(move)
            self._nutrientStores = new_nutrient_store

        self.logger = gutsim.vessel.Logger(
            vessel=self,
            bacteria_graphing_start_time=bacteria_graphing_start_time,
            graphPath=graphPath)
        self.initialise_nutrient_Store(timestep, 24.0)
        # Initialise bacteria in the simulation
        for _ in range(init_Grf):
            self._bacteria.append(
                gutsim.bacteria.Guild_rf_f(timestep=timestep))
        for _ in range(init_Grm):
            self._bacteria.append(
                gutsim.bacteria.Guild_rm_m(timestep=timestep))
        for _ in range(init_Gpf):
            self._bacteria.append(
                gutsim.bacteria.Guild_pf_f(timestep=timestep))
        for _ in range(init_Gpm):
            self._bacteria.append(
                gutsim.bacteria.Guild_pm_m(timestep=timestep))
        for _ in range(init_Gmm):
            self._bacteria.append(gutsim.bacteria.Guild_m_m(timestep=timestep))
        for _ in range(init_Gmf):
            self._bacteria.append(
                gutsim.bacteria.Guild_mf_f(timestep=timestep))
        shuffle(self._bacteria
                )  # Ensure bacteria are well mixed prior to simulation.

        print('------- Nutrient inputs --------')
        for regime in self.nutrientInputs:
            print('hourly nutrient inputs:')
            print(regime.regime_string())
        print('--------------------------------')

        current_time = 0.0
        # Cumulative count of how much digesta and bacteria should have been excreted. This is stored as float, and
        # excretion takes place when threshold of a nutrient store of sufficient size (or a whole bacteria) is reached.
        digesta_to_excrete = 0.0
        bacteria_to_excrete_cumulative = 0.0
        self.logger.bacterGraphs = bacteria_graphing_start_time
        self.logger.log(self._bacteria, current_time)

        # Step through time
        while current_time < endtime:
            current_time += timestep
            # Nutrients added. New nutrients (from upper GI tract and mucin) are added to new object, and added to front
            # of nutrient store list.
            # Note that mucin is then redistributed along the length of the gut.
            nutStore = Nutrients()
            for ni in self.nutrientInputs:
                if ni.is_active(current_time):
                    nutStore.add(ni.getNutrients(current_time, timestep))
            # Clone the nutrient record for logging.
            nutrient_input = nutStore.clone()
            # Put new nutrient record at start of GIT.
            self._nutrientStores.insert(0, nutStore)
            # Secrete mucus evenly along the entire GIT.
            Cm = nutStore.Cm
            Nm = nutStore.Nm
            nutStore.Cm = 0.0
            nutStore.Nm = 0.0
            Cmi = float(Cm) / len(
                self._nutrientStores)  # Secrete mucus uniformly along GIT.
            Nmi = float(Nm) / len(self._nutrientStores)
            for ni in self._nutrientStores:
                ni.add_quantities(Cm=Cmi, Nm=Nmi)

            if verbose:
                totNutrients = Nutrients()
                for n in self._nutrientStores:
                    totNutrients.add(n)
                print('ct = ' + str(current_time) + ' ' +
                      self.logger.string_state() + '\n\t' + str(totNutrients))

            inoculum()
            if len(self._bacteria) > 0:  # No point shuffling nothing.
                bacteria_peristalsis()
            if len(self._nutrientStores) > 0:
                nutrient_peristalsis()

            # Step each bacteria. Each bacteria is assigned a nutrient store from which to extract nutrients.
            # There are likely multiple bacteria feeding from each store.
            bPerNS = float(len(self._bacteria)) / len(self._nutrientStores)
            # Build up a new list of bacteria, representing the GIT, as the current list is iterated.
            nextGIT = []
            # Scale nutrients to the desired level (affects total number of bacteria).
            # This is reversed after bacteria have consumed and grown (see below)
            nutStore.scale_by_factor(scale_factor)
            for ns in self._nutrientStores:
                ns.scale_by_factor(scale_factor)

            for i, b in enumerate(self._bacteria):
                # Calculate which index in the nutrients store this bacteria corresponds to.
                # Int used here always rounds down.
                # Even if bPerNS is not a whole number, bacteria will broadly still access the correct nutrient store.
                iNS = int(i / bPerNS)
                # Returns nutrients consumed, and either a new bacteria object or None.
                consumed, child = b.step(self._nutrientStores[iNS])
                self._nutrientStores[iNS].subtract(consumed)
                non_absorbable_organic_matter = consumed.total_fermentable_quantity(
                ) * non_absorbable_organic_matter_generation_rate
                self._nutrientStores[iNS].add_quantities(
                    other_organic_matter=non_absorbable_organic_matter)
                # New bacteria go in front of the current bacterium.
                if child is not None:
                    nextGIT.append(child)
                nextGIT.append(b)  # Add the current bacterium also.
            # Update for next time step.
            self._bacteria = nextGIT

            # Scale nutrient quantities back to grams.
            for ns in self._nutrientStores:
                ns.scale_by_factor(1.0 / scale_factor)

            # Perform mouse defecation.
            # Awake for first 12 hours of day (nighttime; mice are nocturnal).
            # Having to convert to ints here, because floats and modulo operator are incompatible.
            if int(current_time * 10) % 240 < 120:
                excrete_timestep = excretion_rate * timestep
            else:
                # During the light phase (less activity), excretion rate drops to half of active phase.
                # This gives 2/3 vs 1/3 pattern of total excretion across these phases.
                excrete_timestep = excretion_rate * 0.5 * timestep
            digesta_weight = sum(
                [ns.total_digesta_weight() for ns in self._nutrientStores])
            # If the GIT's carrying capacity is exceeded, increase the excretion rate.
            if excess_digesta(digesta_weight):
                excrete_timestep *= 5.0  # Value of 5 is arbitrarily chosen.
            # Keep a cumulative count of how much digesta should have been excreted. When the quantity of nutrient
            # in the last nutrient store is greater than this cumulative count, delete the nutrient store.
            digesta_to_excrete += digesta_weight * excrete_timestep
            # Can't continue to delete if there's nothing left
            while len(self._nutrientStores) > 0 and \
                    self._nutrientStores[-1].total_digesta_weight() <= digesta_to_excrete:
                digesta_to_excrete -= self._nutrientStores[
                    -1].total_digesta_weight()
                del (self._nutrientStores[-1])

            # Quantity to be excreted
            bacteria_to_excrete_cumulative += excrete_timestep * len(
                self._bacteria)
            bacteria_excreted = int(bacteria_to_excrete_cumulative)
            if bacteria_excreted > 0:  # Safety. list[-0:] = [] will delete the entire list.
                self.bacteria_excreted_logging += bacteria_excreted  # Used for logging.
                bacteria_to_excrete_cumulative -= float(bacteria_excreted)
                self._bacteria[-bacteria_excreted:] = []

            # Perform logging of bacterial numbers.
            self.logger.log(self._bacteria,
                            current_time,
                            nutrient_input=nutrient_input)
示例#18
0
        def nutrient_peristalsis():
            """
            Moves nutrients between nutrient stores; a low level of mixing resulting from peristalsis. 
            """
            # Gaussian diffusion represent diffusion as a result of peristalsis, IE, how much diffusion results from
            # each peristalsis event. This variable indicates how many peristalsis events are represented in the current
            # time step (time step may represent more than one peristalsis event).
            diffusion_rate = peristalsis_rate * timestep
            sigma_time_adjusted = nutrient_peristalsis_rate * diffusion_rate
            num_nutrient_stores = len(self._nutrientStores)
            length_per_nutrient_store = gut_length / num_nutrient_stores
            # Create a new store, which will be populated with nutrients.
            new_nutrient_store = [Nutrients() for _ in self._nutrientStores]

            # Location of this store along the gut. Conceptualized as follows. Nutrient sources ordered sequentially.
            # Their locations defined as cx. For integration, need to know the lower and upper boundaries, which
            # are given in factors of l (l=length of nutrient source in the gut, and can vary with number of
            # nutrient sources).
            #
            # 0l           1l           2l           3l           4l           5l
            # -------------------------------------------------------------------
            # |    c0      |    c1      |    c2      |    c3      |    c4      | ...
            # -------------------------------------------------------------------
            #
            # Normalized gaussian curve integrates to 1, hence its integral describes the diffusion of nutrients
            # into a specified length of gut.
            # Pre-compute the diffusion quantities by index distance. This is an efficiency saving. Since the
            # distribution changes only for the number of nutrient stores, which only changes between time steps,
            # the same distribution applies for every nutrient store in a timestep.
            # Need compute only one half of the distribution, as it is symmetrical.
            diffusion_by_index_difference = [None] * len(self._nutrientStores)
            # Declared here for efficiency. The lower bound for nutrient source n+1 = the supper bound for nutrient
            # source n (so don't have to re-compute it).
            sink_upper_distance = None
            for k in range(len(self._nutrientStores)):
                loc_source = 0.5 * length_per_nutrient_store
                if sink_upper_distance is None:  # No boundaries have been calculated for first nutrient source.
                    sink_lower_distance = (
                        k * length_per_nutrient_store) - loc_source
                else:  # Adopt upper boundary of the previous nutrient source location.
                    sink_lower_distance = sink_upper_distance
                sink_upper_distance = (
                    (k + 1) * length_per_nutrient_store) - loc_source
                integral_lower = stats.phi_gauss(sink_lower_distance,
                                                 mu=0,
                                                 sigma=sigma_time_adjusted)
                integral_upper = stats.phi_gauss(sink_upper_distance,
                                                 mu=0,
                                                 sigma=sigma_time_adjusted)
                proportion_diffused = integral_upper - integral_lower
                diffusion_by_index_difference[k] = proportion_diffused
            # Diffusion only performed over ranges where a substanital difference in concentration is incurred.
            # This saves computational expense, and makes little difference to simulation dynamics.
            # Here we ascertain the distance over which (meaningful) diffusion will be performed.
            negligible_diffusion_distance = 0
            negligible_diffusion_threshold = 0.05 / len(self._nutrientStores)
            for i, diff in enumerate(diffusion_by_index_difference):
                if diff < negligible_diffusion_threshold:  # Not worth performing diffusion beyond this spatial range.
                    negligible_diffusion_distance = i
                    break

            # Scan through each existing nutrient store, and distribute nutrients
            for i, n_source in enumerate(self._nutrientStores):
                # Proportion of nutrient store contents not moved anywhere because Gaussian stretches from -Inf to Inf.
                # This will be retained in the current nutrient store location.
                remaining = 1.0
                # Start from difference of 1, 0 = the source, handled separately below.
                # Diffusion distribution is symmetrical, so calculate both sides of i (getting progressively further
                # away) simultaneously. Is more efficient, as not duplicating calculations.
                for index_difference in range(1,
                                              negligible_diffusion_distance):
                    proportion_diffused = diffusion_by_index_difference[
                        index_difference]  # use lookup table.
                    move = n_source.proportion_query(proportion_diffused)
                    i_low = i - index_difference
                    if i_low >= 0:
                        new_nutrient_store[i - index_difference].add(move)
                        remaining -= proportion_diffused
                    i_high = i + index_difference
                    if i_high <= len(self._nutrientStores) - 1:
                        new_nutrient_store[i + index_difference].add(move)
                        remaining -= proportion_diffused
                # Any nutrient not already dealt with (Gaussian stretches from -Inf to Inf) is retained
                move = n_source.proportion_query(remaining)
                new_nutrient_store[i].add(move)
            self._nutrientStores = new_nutrient_store
示例#19
0
def diet_analysis(mice):
    print('\nPERFORMING DIET ANALYSIS\n')
    diet_code_file = open('diet-analysis/diet-composition-per-mouse.csv', 'w')
    relNutFile = open('diet-analysis/nutrient_rel_abundances.csv', 'w')
    relNutFile.write(
        '#{:8s},{:16s},{:16s},{:16s},'.format(
            'mouse-ID', 'carb-intake-KJ/d', 'prot-intake-KJ/d',
            'fat-intake-KJ/d') + '{:7s},{:7s},{:7s},{:7s},{:7s},'.format(
                'relCw', 'relCd', 'relCm', 'relNf', 'relNm') +
        '{:7s},{:7s},{:7s},{:7s},{:7s},'.format('inCw', 'inCd', 'inCm', 'inNf',
                                                'inNm') +
        '{:7s},{:7s},{:7s},{:7s},{:7s},'.format('siCw', 'siCd', 'siCm', 'siNf',
                                                'siNm') +
        '{:7s},{:7s},{:7s},{:7s},{:7s},'.format('siPCw', 'siPCd', 'siPCm',
                                                'siPNf', 'siPNm') +
        '{:7s},{:7s},{:7s},{:7s},{:7s},'.format(
            'colicCw', 'colicCd', 'colicCm', 'colicNf', 'colicNm') +
        '{:7s},'.format('Nf:Nm') +
        '{:14s},{:14s},{:14s},{:14},{:14},{:14s},'.format(
            'cecum_relCw', 'cecum_relCd', 'cecum_relCmuc', 'cecum_relCcas',
            'cecum_relNmuc', 'cecum_relNcas') + '\n')

    diet_code_file.write(
        '%5s, %10s, %6s, %6s, %6s, %6s, %6s\n' %
        ('#ID', 'diet code', 'Nf_g', 'Cw_g', 'Cd_g', 'Nm_g', 'Cm_g'))
    for i, mouse_num in enumerate(mice.keys()):
        mouse = mice[mouse_num]
        # This code is used for writing nutrient relative abundances to the file system.
        ci = mouse.daily_wheatstarch_kj + mouse.daily_dextrinised_kj + mouse.daily_sucrose_kj
        pi = mouse.daily_nitrogen_kj
        fi = mouse.daily_fat_kj  # Fat intake

        # Instantiate variables, values cumulatively added based on each nutrient input regimen.
        intake = Nutrients()
        colic = Nutrients()
        si_absorb = Nutrients()
        si_prop = Nutrients()
        for nIn in mouse.nutrientInputs:
            intake.add(
                nIn.dailyIntake
            )  # A Nutrients object representing daily generation of nutrients.
            colic.add(nIn.daily_colic_input)
            si_absorb.add(nIn.daily_si_absorbed)
            si_prop.add(nIn.si_absorption_prop)

        # These are by weight of macronutrient's carbon/nitrogen atoms.
        totC_weight = intake.carbon_content()
        totN_weight = intake.nitrogen_content()

        # These are percentages by weight of macronutrient carbon content.
        rel_carbon_Cw = 100 * nutrients.carbon_content_carbohydrate(
            intake.Cw) / totC_weight
        rel_carbon_Cd = 100 * nutrients.carbon_content_carbohydrate(
            intake.Cd) / totC_weight
        rel_carbon_Cs = 100 * nutrients.carbon_content_carbohydrate(
            intake.Cs) / totC_weight
        rel_carbon_Cm = 100 * nutrients.carbon_content_carbohydrate(
            intake.Cm) / totC_weight
        rel_nitrogen_Nf = 100 * nutrients.nitrogen_content_protein(
            intake.Nf) / totN_weight
        rel_nitrogen_Nm = 100 * nutrients.nitrogen_content_protein(
            intake.Nm) / totN_weight
        ratio_nitrogen_NFNm = intake.Nf / intake.Nm

        # These are percentages by weight of macronutrient carbon content.
        # Considers macronutrients available to bacteria, i.e. feed macronutrients post-small intestine.
        cecum_totC_weight = colic.carbon_content(
        )  # These are by weight of macronutrient's carbon/nitrogen atoms.
        cecum_totN_weight = colic.nitrogen_content()

        print('cecum C weight ' + str(cecum_totC_weight) +
              ' ; total weight = ' + str(totC_weight))
        cecum_rel_carbon_Cw = 100 * nutrients.carbon_content_carbohydrate(
            colic.Cw) / cecum_totC_weight
        cecum_rel_carbon_Cd = 100 * nutrients.carbon_content_carbohydrate(
            colic.Cd) / cecum_totC_weight
        cecum_rel_carbon_Cs = 100 * nutrients.carbon_content_carbohydrate(
            colic.Cs) / cecum_totC_weight
        cecum_rel_carbon_mucin = 100 * \
                                 (nutrients.carbon_content_carbohydrate(colic.Cm) + nutrients.carbon_content_protein(colic.Nm)) \
                                 / cecum_totC_weight
        # Some carbon comes from casein too.
        cecum_rel_carbon_cas = 100 * nutrients.carbon_content_protein(
            colic.Nf) / cecum_totC_weight

        cecum_rel_nitrogen_mucin = 100 * nutrients.nitrogen_content_protein(
            colic.Nm) / cecum_totN_weight
        cecum_rel_nitrogen_cas = 100 * nutrients.nitrogen_content_protein(
            colic.Nf) / cecum_totN_weight

        relNutFile.write(
            '{:9d},{:10.10f},{:10.10f},{:10.10f},'.format(
                i, ci, pi, fi)  # Mouse index, then carb, prot and fat intakes
            # Relative abundances of carbon and nitrogen, by carbon atom weight of INTAKE/secreted quantities.
            + '{:.17f},{:.17f},{:.17f},{:.17f},{:.17f},'.format(
                rel_carbon_Cw, rel_carbon_Cd, rel_carbon_Cm, rel_nitrogen_Nf,
                rel_nitrogen_Nm)
            # Nutrients eaten
            + '{:.17f},{:.17f},{:.17f},{:.17f},{:.17f},'.format(
                intake.Cw, intake.Cd, intake.Cm, intake.Nf, intake.Nm)
            # Absolute quantity absorbed by the SI
            + '{:.17f},{:.17f},{:.17f},{:.17f},{:.17f},'.format(
                si_absorb.Cw, si_absorb.Cd, si_absorb.Cm, si_absorb.Nf,
                si_absorb.Nm)
            # Proportion of eaten nutrients absorbed by the SI
            + '{:.17f},{:.17f},{:.17f},{:.17f},{:.17f},'.format(
                si_prop.Cw, si_prop.Cd, si_prop.Cm, si_prop.Nf, si_prop.Nm)
            # Quantity reaching the colon.
            + '{:.17f},{:.17f},{:.17f},{:.17f},{:.17f},'.format(
                colic.Cw, colic.Cd, colic.Cm, colic.Nf, colic.Nm) +
            '{:.17f},'.format(ratio_nitrogen_NFNm)
            # Relative abundances of carbon and nitrogen (by atom weight, not total macronutrient weight), given
            # availability to bacteria. i.e., post-small intestine.
            + '{:14.2f},{:14.2f},{:14.2f},{:14.2f},{:14.2f},{:14.2f}'.format(
                cecum_rel_carbon_Cw, cecum_rel_carbon_Cd,
                cecum_rel_carbon_mucin, cecum_rel_carbon_cas,
                cecum_rel_nitrogen_mucin, cecum_rel_nitrogen_cas) + '\n')
        diet_code_file.write('%5d, %10s, %6f, %6f, %6f, %6f, %6f\n' %
                             (i, mouse.dietCode, intake.Nf, intake.Cw,
                              intake.Cd, intake.Nm, intake.Cm))

    diet_code_file.close()
    relNutFile.close()